Have you ever thought, "If only my AS/400 program could read a PC file directly from the shared folders, I'd have it made!" Then, in walks the boss, who says, "I have this new project...."
Suddenly, a wistful thought escalates to a frantic search for the technical knowledge to pull yet another rabbit out of your hat. Fortunately, you remember hearing about the lesser-known system APIs that enable AS/400 applications to work transparently with PC files residing on the shared folders-Hierarchical File System (HFS) APIs.
With a knowledge of HFS APIs, you'd be in a better position to jump into that new project the boss has planned. When you've finished reading this article, you won't need magic hats or rabbits-knowledge of HFS APIs will be your sleight of hand, and techniques of modularity will be your tool for reproduction. It's all a matter of getting the pieces to fit together.
As the need for distributed systems continues to dominate our industry, the landscape most of us are accustomed to is changing drastically. Some things take a bit more time to change than others, however. For one reason or another, management may wish some functions (such as the payment and receipt of cash) to remain host-centric, while other functions (such as the entry of bills or invoices) are served by distributed applications. Yet, as is often the case, one is in opposition to the other, and the need to seamlessly access data from a diverse set of file systems becomes even more critical to the productivity and sanity of users.
In today's computing environment, it is common to need to upload data from DOS, OS/2, UNIX, or other file systems. These other file systems may be numerous and geographically dispersed, making wide area network (WAN) access an expensive option. If you're not careful to select development techniques that promote consolidation and integration of user activities, applications can become fragmented and start to look like a jigsaw puzzle. Getting the pieces to fit together smoothly can be challenging.
You could take several approaches to access PC file data. One might be to have remote users send PC (ASCII) text file data on diskettes to the corporate office. However, this has the disadvantages of excessive postal charges, slow response time, and poor error-correction facilities (if the data is wrong, the remote user must send another diskette). Additional considerations are the cost of diskettes (since these might need to be sent more than once a week from several locations), potential damage in transit, and the possibility of being infected by viruses arising from such widespread diskette circulation.
Then, once the diskettes arrive for processing, the PC file data must be uploaded to an AS/400 file member for corporate systems processing. Such a transformation creates additional steps for the corporate staff, causing a loss in direct traceability. For example, the data flows from the PC file to a transient AS/400 file member to the corporate payable batch file, instead of directly from the PC file to the corporate payables batch file.
With each group of invoices contained in a PC file being assigned a batch number, an audit trail is made that carries the identity through the system for the life of the data. However, when data is uploaded to transient file members, identification may change because of incompatibility of naming conventions between file systems. For example, A&P0494.TXT is entirely appropriate for an MS-DOS file name, but inappropriate for an AS/400 file name.
Some clear advantages come with using AS/400 shared folders as a repository for data awaiting integration into AS/400 files: the elimination of physical handling of media; good delivery response (you can connect and deposit PC files on shared folders); and, for users, conceptual association with a common technique used by many BBSs today-batch file (or offline) transfer (connect-deposit-disconnect).
Only one obstacle remains: that of direct access of PC file data residing on the AS/400 shared folders from an AS/400 application.
Why direct access to shared folders data, anyway? After all, with the Copy from PC Document (CPYFRMPCD) command, you can copy PC file data residing on an AS/400 folder to an AS/400 file member with automatic ASCII-to-EBCDIC data translation. However, if interactive response is an important consideration for your application, such an approach produces less than acceptable results. Using HFS APIs requires the programmer to handle the ASCII-to-EBCDIC translation, but when both techniques were benchmarked, CPYFRMPCD required 3-5 times as long to process as the HFS API method.
Suppose you have a process whereby remote AS/400 users can dial up and deposit PC file data into AS/400 shared folders-sort of like a BBS or offline E-mail. All you need is a way for local (corporate) AS/400 users to get to the data. With HFS APIs, you can display a list of folders to the local users for selection. After selection, the users are presented with a list of PC shared folder files (from the selected folder) like that illustrated in 1. The files can in turn be selected for further processing. Although the Display Folder (DSPFLR) command with the OUTFILE option selected could also have been used to build this list, interactive performance would have suffered significantly.
Suppose you have a process whereby remote AS/400 users can dial up and deposit PC file data into AS/400 shared folders-sort of like a BBS or offline E-mail. All you need is a way for local (corporate) AS/400 users to get to the data. With HFS APIs, you can display a list of folders to the local users for selection. After selection, the users are presented with a list of PC shared folder files (from the selected folder) like that illustrated in Figure 1. The files can in turn be selected for further processing. Although the Display Folder (DSPFLR) command with the OUTFILE option selected could also have been used to build this list, interactive performance would have suffered significantly.
Accessing the data directly from the shared folders can be accomplished through HFS APIs. Shared folders is a document library services (DLS) file system and uses a hierarchical file system architecture similar to that used by MS-DOS for the storage and management of user files. The architecture organizes files and programs according to the directorysubdirectoryfile trees most of us are acquainted with, as illustrated in 2.
Accessing the data directly from the shared folders can be accomplished through HFS APIs. Shared folders is a document library services (DLS) file system and uses a hierarchical file system architecture similar to that used by MS-DOS for the storage and management of user files. The architecture organizes files and programs according to the directorysubdirectoryfile trees most of us are acquainted with, as illustrated in Figure 2.
IBM developed the HFS APIs to enable an AS/400 application to extract data directly from a DOS-type or byte-stream file without having to upload that file to an AS/400 file before it could be used. However, interfacing with those APIs can be complex in comparison to typical AS/400 development. Such complexity precludes, or at least makes difficult, using these APIs on a widespread basis. However, by developing and documenting a set of globally callable functions, you can make the services that are available through the HFS APIs more appealing for use in a greater number of applications. To make these global functions more extensible, we take a modular approach and construct black box interface programs that make it easy for any program in your application to open, read, and close PC files residing on the shared folders.
We can build a generic utility program that services our HFS API needs, so client (requester) applications don't have to know its implementation to use it. By creating a public interface with a standard set of functions that embody HFS API services, we can hide the complexity of their implementation from client applications.
As depicted in 3, the client (requester) program first issues an *OPEN request to the black box utility to open the byte-stream file. Next, the client program issues consecutive *READ requests to extract the PC file records one at a time. Finally, the client program issues a *CLOSE request to close the stream file. The HFS APIs needed to accomplish each of these objectives are presented in 3 as calls from our black box program, but they are not visible to client programs. The client program is thus insulated from the complexity of arbitrating directly with the HFS APIs for their services.
As depicted in Figure 3, the client (requester) program first issues an *OPEN request to the black box utility to open the byte-stream file. Next, the client program issues consecutive *READ requests to extract the PC file records one at a time. Finally, the client program issues a *CLOSE request to close the stream file. The HFS APIs needed to accomplish each of these objectives are presented in Figure 3 as calls from our black box program, but they are not visible to client programs. The client program is thus insulated from the complexity of arbitrating directly with the HFS APIs for their services.
HFS API names begin with Q followed by HF, which designates HFS APIs. The translation API that will be called to convert the ASCII text data read from byte-stream files to EBCDIC for host presentations is designated as a data conversion (DC) API and not a part of the HFS API suite. Each of these APIs are well-documented in the OS/400 System API Reference V3R1.
The black box or generic utility application that will service our PC data extraction needs, shown in part in 4, has as its interface one input parameter and one output parameter. Only the portions of the black box code required to explain the HFS APIs are included here; however, the complete program (XA0020R) can be found on MC-BBS or on the Internet at www.as400.com/mc/prog. (Complete code for another HFS black box program (XA0021R) that returns shared folder directory information can also be found on MC-BBS and at www.as400.com/mc/prog. XA0021R was used by the program that produced the list of invoice files displayed in the pop-up window in 1.)
The black box or generic utility application that will service our PC data extraction needs, shown in part in Figure 4, has as its interface one input parameter and one output parameter. Only the portions of the black box code required to explain the HFS APIs are included here; however, the complete program (XA0020R) can be found on MC-BBS or on the Internet at www.as400.com/mc/prog. (Complete code for another HFS black box program (XA0021R) that returns shared folder directory information can also be found on MC-BBS and at www.as400.com/mc/prog. XA0021R was used by the program that produced the list of invoice files displayed in the pop-up window in Figure 1.)
Some of the fields in the 256-byte input parameter data structure (XA0020), shown in label A of 4, are requester options, while others serve as feedback information to the requester application about the status of the last request. The XA0020 subfields and their usage are as follows:
Some of the fields in the 256-byte input parameter data structure (XA0020), shown in label A of Figure 4, are requester options, while others serve as feedback information to the requester application about the status of the last request. The XA0020 subfields and their usage are as follows:
o FUNCTN=Name of requester function to be performed (required, no defaults). The valid functions are *OPEN, *READ, and *CLOSE.
o FILSYS=File system (optional, defaults to /QDLS when blank).
o PATH=Path name for PC file, including file name (required, no defaults).
o RECLEN=Expected record length of one logical PC file record from the extraction file (required, no defaults).
o LASTR=Last record indicator on a *READ function.
o RESRVD=Bytes reserved for black box services expansion.
o RTNCOD=Return code (0=no errors).
The output parameter data structure (INRECD) shown in label B of 4 is used strictly as an output buffer for data extracted from the PC file. It may be as large as 4KB, but specifying a record length larger than that required by your application will cause the black box utility to perform inefficiently. Specifying too short a record length can cause this utility to abort with a terminal return code (RTNCOD) if the end-of-record indication (X'0D0A') cannot be found.
The output parameter data structure (INRECD) shown in label B of Figure 4 is used strictly as an output buffer for data extracted from the PC file. It may be as large as 4KB, but specifying a record length larger than that required by your application will cause the black box utility to perform inefficiently. Specifying too short a record length can cause this utility to abort with a terminal return code (RTNCOD) if the end-of-record indication (X'0D0A') cannot be found.
To begin the explanation of the stream file APIs in 4, I have defined some constants in label C of 4 to make the code more readable. The utilities' functions are identified in label D. In labels E and F of 4, parameters that will be passed to the Open Stream File (QHFOPNSF) API are initialized. In label F, the important values set are for the error code (ERRCOD) and the open information code (OPNINF). The error code is set to zero to direct the API to send an exception message to the calling application (our generic program) when an error occurs. The OPNINF parameter with a value of '100 200' directs the API to open the file in read-only mode. Other jobs can read this file, but they cannot write to it while it is being used by this application.
To begin the explanation of the stream file APIs in Figure 4, I have defined some constants in label C of Figure 4 to make the code more readable. The utilities' functions are identified in label D. In labels E and F of Figure 4, parameters that will be passed to the Open Stream File (QHFOPNSF) API are initialized. In label F, the important values set are for the error code (ERRCOD) and the open information code (OPNINF). The error code is set to zero to direct the API to send an exception message to the calling application (our generic program) when an error occurs. The OPNINF parameter with a value of '100 200' directs the API to open the file in read-only mode. Other jobs can read this file, but they cannot write to it while it is being used by this application.
Each byte in the OPNINF field has a specific meaning. For example, here's how IBM identifies possible values for the first byte (open action) if the file already exists:
o 0 Do not open the file. Return an error.
o 1 Open the file.
o 2 Replace the existing file.
IBM identifies which operations other jobs can perform on the file (file lock mode) in the fifth byte:
o 1 Deny none.
o 2 Deny write.
o 3 Deny read.
o 4 Deny read/write (exclusive).
The other bytes and their meanings are well-documented in the OS/400 System API Reference V3R1 and will not be discussed in this article.
In label E of 4, the full path, inclusive of the selected document (file) name, is constructed. For example, a file by the name of MAY0494 residing in shared folder INVOICES would appear as /QDLS/INVOICES/MAY0494.TXT.
In label E of Figure 4, the full path, inclusive of the selected document (file) name, is constructed. For example, a file by the name of MAY0494 residing in shared folder INVOICES would appear as /QDLS/INVOICES/MAY0494.TXT.
As you can see, the file system identification must prefix the path name presented to the QHFOPNSF API in label F. A table of the required parameters appears immediately below the call statement of the QHFOPNSF API in label F. The file handle (FILHDL) acquired as output in the QHFOPNSF API will be used by subsequently called APIs.
As shown in 4, one logical PC file record is read from the stream file on the shared folders (with each *READ call service request) with the aid of the Read Stream File (QHFRDSF) API in label G of 4, utilizing the FILHDL acquired by the QHFOPNSF API. The number of bytes to read (#TREAD) is passed by the caller through the input parameter data structure XA0020, subfield RECLEN. Next, in label H of 4, we scan the string read (as defined by INRECD) for the ASCII carriage return character (X'0D') that will signal the end of the record. After that, we translate the extracted string from its current ASCII encoding scheme to EBCDIC for AS/400 processing with the call to the Data Translation (QDCXLATE) API shown in label I.
As shown in Figure 4, one logical PC file record is read from the stream file on the shared folders (with each *READ call service request) with the aid of the Read Stream File (QHFRDSF) API in label G of Figure 4, utilizing the FILHDL acquired by the QHFOPNSF API. The number of bytes to read (#TREAD) is passed by the caller through the input parameter data structure XA0020, subfield RECLEN. Next, in label H of Figure 4, we scan the string read (as defined by INRECD) for the ASCII carriage return character (X'0D') that will signal the end of the record. After that, we translate the extracted string from its current ASCII encoding scheme to EBCDIC for AS/400 processing with the call to the Data Translation (QDCXLATE) API shown in label I.
In label J of 4, using the position of the carriage return obtained in label H, we calculate and reposition the file pointer to the first position following the carriage return (X'0D') and linefeed (X'0A') characters to ready it for the next extraction cycle. The algorithm to calculate the number of bytes to move the file pointer in the byte-stream is DSTTMV = F - (#READ + 1) or, simply stated, "the distance to move the file pointer=(the current position of X'0D' in the extracted string + 2) - (the number of actual characters read + 1)."
In label J of Figure 4, using the position of the carriage return obtained in label H, we calculate and reposition the file pointer to the first position following the carriage return (X'0D') and linefeed (X'0A') characters to ready it for the next extraction cycle. The algorithm to calculate the number of bytes to move the file pointer in the byte-stream is DSTTMV = F - (#READ + 1) or, simply stated, "the distance to move the file pointer=(the current position of X'0D' in the extracted string + 2) - (the number of actual characters read + 1)."
This calculation yields a negative number and has the effect of moving the file pointer backward the number of bytes previously overread, to reposition it to the beginning of the next logical record. This must be accomplished to extract the next logical PC file record since the pointer will, in all probability, be pointing to a position somewhere beyond the beginning of the next logical record after an extraction. Remember, the file pointer is positioned at the end of the actual character string read, which may or may not be the end of the record.
Our client program may have no way of knowing the record length of each file to be extracted. You may reposition the file pointer with the Change File Pointer (QHFCHGFP) API. The end-of-file indication is given when an error is received from QHFCHGFP in an attempt to move the file pointer beyond the end of the file. This causes a normal exit to occur from the loop processing. Once processing has been dispatched for the stream file, you should close it using the Close Stream File (QHFCLOSF) API in label K of 4. In every case, the FILHDL acquired in the QHFOPNSF operation was passed to the APIs for accessing the stream file.
Our client program may have no way of knowing the record length of each file to be extracted. You may reposition the file pointer with the Change File Pointer (QHFCHGFP) API. The end-of-file indication is given when an error is received from QHFCHGFP in an attempt to move the file pointer beyond the end of the file. This causes a normal exit to occur from the loop processing. Once processing has been dispatched for the stream file, you should close it using the Close Stream File (QHFCLOSF) API in label K of Figure 4. In every case, the FILHDL acquired in the QHFOPNSF operation was passed to the APIs for accessing the stream file.
Let's put this concept of reuse through modularity to the test by employing our generic utility program to extract the data in ASCII text PC files residing on the AS/400 shared folders. To accomplish this, we will view the generic utility program as a black box. That is, forget all the details of the generic utility program you just learned; all we should be concerned with to use this utility is what goes into the box (the input parameters or requester options) and what comes out (the feedback indicators and the translated PC data). 5 illustrates the code (not shown in its entirety) required by any client application to use this generic utility application.
Let's put this concept of reuse through modularity to the test by employing our generic utility program to extract the data in ASCII text PC files residing on the AS/400 shared folders. To accomplish this, we will view the generic utility program as a black box. That is, forget all the details of the generic utility program you just learned; all we should be concerned with to use this utility is what goes into the box (the input parameters or requester options) and what comes out (the feedback indicators and the translated PC data). Figure 5 illustrates the code (not shown in its entirety) required by any client application to use this generic utility application.
The section of code entitled "Open a request..." has the requirements for loading the necessary parameters for the call to our generic utility program. The black box program passes the data representing individual records from our selected PC file in the RECBFR data structure already translated to the EBCDIC data format expected by AS/400 programs.
It is of paramount importance to ensure that the options are properly initialized (in the request options parameter) for the call to our generic utility program. As shown in the *OPEN request in label A of 5, the path is the only required piece of information. When left blank, the file system will default to the QDLS system. As shown in the *READ request presented in the $EXTPC subroutine in 5, in addition to setting the last record (LASTR) and RTNCOD indicators to *OFF, in label B we must specify the expected record length for the PC file data being extracted. In the example here, we have chosen 512 bytes as our expected record length. Finally, in label C of 5 (in the section of code entitled "Close a request..."), the only information required is the function name, *CLOSE.
It is of paramount importance to ensure that the options are properly initialized (in the request options parameter) for the call to our generic utility program. As shown in the *OPEN request in label A of Figure 5, the path is the only required piece of information. When left blank, the file system will default to the QDLS system. As shown in the *READ request presented in the $EXTPC subroutine in Figure 5, in addition to setting the last record (LASTR) and RTNCOD indicators to *OFF, in label B we must specify the expected record length for the PC file data being extracted. In the example here, we have chosen 512 bytes as our expected record length. Finally, in label C of Figure 5 (in the section of code entitled "Close a request..."), the only information required is the function name, *CLOSE.
One final note: V3R1 of OS/400 introduces the Integrated File System (IFS), a feature for handling and manipulating files from diverse file systems. Besides handling the record-oriented file system with which we are all familiar (QSYS.LIB), interaction with four other types of file systems (root, QOpenSys, QDLS, and QLANSrv) that deal with byte-stream files is integrated into the already robust set of OS/400 file commands, menus, and displays.
After a brief review of the programming interfaces provided for the IFS, though, you quickly find that only one language is supported with a suitable programming interface to IFS functions: ILE C/400. For those installations still managing legacy RPG III or even RPG II code, ILE seems a bit too far in the future, to say nothing of ILE C/400. Regardless, ILE C/400 does offer a useful set of functions to open, read, write, and close byte-stream files. However, extended attributes (EAs) cannot be accessed through ILE C/400 functions. For those, you must still use the HFS APIs. You can read more about the IFS and ILE C/400 functions in the references listed at the end of this article.
As you can see from this example, you could easily construct commands, such as an AS/400 version of the DOS command TYPE, using this same generically called program, without having any knowledge of HFS APIs or shared folders. In fact, I wrote a TYPE utility for the AS/400 that allows any AS/400 user to view the contents of a PC file stored on a shared folder, even from a terminal. You can find the code for the TYPE utility on the MC-BBS or at www.as400.com/mc/prog.
Jim D. Barnes is the informations systems director of the Morningstar Group, based in Dallas, Texas. He has been a professional developer of software on the AS/400 and S/38 for over 13 years and is currently interested in object-oriented technology and its practical application in client/server development for the AS/400.
The Hierarchical File System APIs
Figure 1: Selecting PC Shared Folders Files from an AS/400 Application
AP9999T1 Load and Edit Transmitted Invoices 5/27/95 .................................. : * Transfer Invoices * : Type options, press Enter. : South Dallas Distribution : 1=Select : : : Type options, press Enter. : Opt Location Location Name : 1=Select : 1 DALLAS South Dallas Distribut: : DENVER Denver Area Distributi: MAY0294.TXT : CHICAGO Chicago A & P Distribu: MAY0494.TXT : : MAY0694.TXT : : : : : : : : Bottom : : F1=Help F12=Cancel : : F15=Move F21=Print list : : : :................................: Bottom F1=Help F3=Exit F7=Backward F8=Forward F12=Cancel F21=Print list Your Company Name, LTD. 1994.The Hierarchical File System APIs
Figure 2: The Hierarchical File System
The Hierarchical File System APIs
Figure 3: An HFS Black Box Program
The Hierarchical File System APIs
Figure 4: Partial Code for the RPG HFS Black Box Program
I*********************************************************************** I* Requester Input Parameter. I*********************************************************************** IXA0020 DS 256 I 1 10 FUNCTN I 11 20 FILSYS I 21 83 PATH I P 84 860RECLEN I 87 87 LASTR I 88 255 RESRVD I 256 256 RTNCOD I*********************************************************************** I* Requester Output Parameter. I*********************************************************************** IINRECD DS 4096 I 1 1 RECBFR I*********************************************************************** I* Program defined constants. I*********************************************************************** I '/QDLS' C @QDLS I '9' C @ERR I X'0D' C @CRRTN I X'0A' C @LNFED I X'20' C @HEX20 I 'QCPFMSG ' C @MSGF I 'QSYS ' C @MSGLB C******************************************************************** * *--------- Reinitialize when the current client requester is not the *--------- same as the last (indicating a proper "Close" was not *--------- initiated). * C CURPGM IFNE LSTPGM C EXSR $INZSR C MOVELCURPGM LSTPGM C ENDIF * *--------- Scope of valid stream file operations include "open", *--------- "read" and "close". All other operations are invalid. * C FUNCTN CASEQ'*OPEN' $OPNSF C FUNCTN CASEQ'*READ' $REDSF C FUNCTN CASEQ'*CLOSE' $CLOSF C CAS $ERRSF C ENDCS * *--------- The program is returned with *INLR *OFF. This terminates *--------- it but keeps it resident (TSR) to substantially improve *--------- CALL performance. * C RETRN C******************************************************************** C $INZSR BEGSR Initialize C******************************************************************** C *ENTRY PLIST C PARM XA0020 C PARM INRECD * *--------- Initialize variables required for stream file option *--------- defaults. * C MOVE *ZEROS PTHLEN C MOVE *OFF RTNCOD C MOVE *ZEROS MSGLEN C MOVE *ZEROS MSGSTK C ' ':@HEX20XLATEASC20:1 ASC20 * C MOVE *ZEROS IJ 30 * *--------- Set return code to '1' for NO path specified and end *--------- program. * C PATH IFEQ *BLANKS C MOVE '1' RTNCOD C EXSR $SNDMG C EXSR $ENDPG C ENDIF * *--------- When the input file system name is blank, default the *--------- shared folders file system, "QDLS". * C FILSYS IFEQ *BLANKS C MOVEL@QDLS FILSYS C ENDIF * *--------- Compile complete DLS path name (adding HFS identifier *--------- for file system used by folders - QDLS). Calculate *--------- total path length. * C MOVE *BLANKS PTHNAM 63 C MOVELPATH FWDSLH 1 C PTHNAM CAT FILSYS:0 PTHNAM * C FWDSLH IFNE '/' C PTHNAM CAT '/':0 PTHNAM C ENDIF * C PTHNAM CAT PATH:0 PTHNAM C ' ' SCAN PTHNAM IJ 30 C *IN30 IFEQ *ON C IJ ANDGT*ZERO C SUB 1 IJ C ELSE C Z-ADD63 IJ C ENDIF C Z-ADDIJ PTHLEN C*-------- C ENDSR C******************************************************************** C $OPNSF BEGSR Open Stream File C******************************************************************** C MOVE *BLANKS FILHDL C MOVEL'100 200' OPNINF C MOVE *OFF ACTTKN C Z-ADD*ZERO ERRCOD C Z-ADD*ZEROS TBLLEN * *--------- Open byte-stream file for defined path and file. * C CALL 'QHFOPNSF' 68 OPEN FILE C PARM FILHDL C PARM PTHNAM C PARM PTHLEN C PARM OPNINF C PARM ATRTBL 1 C PARM TBLLEN C PARM ACTTKN C PARM ERRCOD * * Required Parameter Group: * * 1 Open file handle Output Char(16) * 2 Path name Input Char(*) * 4 Open information Input Char(10) * 3 Path name length Input Binary(4) * 5 Attribute information table Input Char(*) * 6 Length of attribute infor- Input Binary(4) * mation table * 7 Action taken Output Char(1) * 8 Error code I/O Char(*) or * Binary(4) * * C *IN68 IFEQ *ON C MOVE '3' RTNCOD C EXSR $SNDMG C EXSR $ENDPG C ENDIF C*-------- C ENDSR C******************************************************************** C $REDSF BEGSR Read Stream File C******************************************************************** * *--------- Read and translate byte-stream file. Then reposition *--------- byte-stream pointer to next logical record. Cycle *--------- through the stream file until end-of-file indication *--------- given by failure in repositioning. * C Z-ADDRECLEN #TREAD C Z-ADD*ZEROS #READ C Z-ADD*ZERO ERRCOD * *--------- Clear record area to ASCII X'20' which is the same as *--------- EBCDIC X'40' or blank. * C MOVELASC20 INRECD * *--------- Read stream file bytes. * C CALL 'QHFRDSF' 68 READ ERROR C PARM FILHDL C PARM INRECD C PARM #TREAD C PARM #READ C PARM ERRCOD * * Required Parameter Group: * * 1 Open file handle Input Char(16) * 2 Data buffer Input Char(*) * 3 Bytes to read Input Binary(4) * 4 Bytes actually read Input Binary(4) * 5 Error code I/O Char(*) or * Binary(4) * C *IN68 IFEQ *OFF * *--------- Scan for ASCII carriage return code signalling end *--------- of PC file record. Use this to replace with HEX20 or *--------- ASCII blanks, as well as to change position of stream *--------- file pointer back to first byte after X'0D0A' or *--------- carriage return and linefeed codes, signalling the *--------- beginning of the next PC file record. * C MOVE *ZEROS F 30 C @CRRTN SCAN INRECD F 31 C *IN31 IFEQ *ON C MOVEAINRECD INA C MOVEAASC20 INA,F C MOVEAINA INRECD C ELSE C MOVE *ON *IN68 C ENDIF * C *IN68 IFEQ *OFF * *--------- Increment 'F' by two to put it beyond the X'0D'/X'0A' *--------- string or end-of-record. * C ADD 2 F * *--------- Translate the retrieved ASCII buffer to EBCDIC for *--------- AS/400 processing. * C CALL 'QDCXLATE' 68 CVT TO EBCDIC C PARM RECLEN INRLEN 50 C PARM INRECD C PARM 'QEBCDIC' SBCDNM 10 C PARM 'QSYS' SBCSLB 10 * C *IN68 IFEQ *OFF * *--------- Change stream file pointer to the beginning of the *--------- next PC file record. * C #READ ADD 1 BYTRED 30 C F SUB BYTRED FPA 30 C CALL 'QHFCHGFP' 68 CHANGE FILE PTR C PARM FILHDL C PARM '1 ' MOVINF 6 C PARM FPA DSTTMV C PARM *ZERO NEWOFS C PARM *ZERO ERRCOD * * * Required Parameter Group: * * 1 Open file handle Input Char(16) * 2 Move information Input Char(6) * 3 Distance to move Input Binary(4) * 4 New offset Output Binary(4) * 5 Error code I/O Char(*) or * Binary(4) * * C MOVE *IN68 LASTR * C ELSE C MOVE '7' RTNCOD C ENDIF * C ELSE C MOVE '8' RTNCOD C ENDIF * C ELSE C MOVE '9' RTNCOD C ENDIF * C RTNCOD IFNE *OFF C EXSR $SNDMG C EXSR $ENDPG C ENDIF C*--------- C ENDSR C******************************************************************** C $CLOSF BEGSR Close Stream File C******************************************************************** * *--------- End stream file processing. * C Z-ADD*ZERO ERRCOD * *--------- Close stream file. * C CALL 'QHFCLOSF' 68 CLOSE ERROR C PARM FILHDL C PARM ERRCOD * * * Required Parameter Group: * * 1 Open file handle Input Char(16) * 2 Error code I/O Char(*) or * Binary(4) * C RTNCOD IFEQ *OFF C *IN68 ANDEQ*ON C MOVE '5' RTNCOD C EXSR $SNDMG C EXSR $ENDPG C ENDIF C*--------- C ENDSR C******************************************************************** C $ENDPG BEGSR End Program C******************************************************************** C MOVE *ON *INLR C RETRN C*--------- C ENDSR
The Hierarchical File System APIs
Figure 5: Partial Code for the Interface to the HFS Black Box Program
Open a request... C******************************************************************** C *INZSR BEGSR INITIALIZE C******************************************************************** C *ENTRY PLIST C PARM INPPTH 50 * *--------- Initialize all required default field values. * C MOVE *ZEROS BYTRCV * *--------- Flip back slashes to forward slashes where found. * C '':'/' XLATEINPPTH INPPTH * *--------- Call the generic program for extracting byte-stream file data *--------- from files residing on AS/400 shared folders. * C MOVE *BLANKS XA0020 C MOVEL'*OPEN' FUNCTN C MOVELINPPTH PATH C MOVE *OFF LASTR C MOVE *OFF RTNCOD * C CALL 'XA0020R' 68 OPEN STREAM FILE C PARM XA0020 C PARM RECBFR * C *IN68 IFEQ *ON C RTNCOD ORNE *OFF C MOVE *ON *INLR C RETRN C ENDIF C*-------- C ENDSR * C******************************************************************** C $EXTPC BEGSR EXTRACT PC DATA C******************************************************************** C MOVE *BLANKS XA0020 C MOVEL'*READ' FUNCTN C Z-ADD512 RECLEN C MOVE *OFF RTNCOD C MOVE *OFF LASTR * C *IN68 DOWEQ*OFF C RTNCOD ANDEQ*OFF C LASTR ANDEQ*OFF * C CALL 'XA0020R' 68 READ STREAM FILE C PARM XA0020 C PARM RECBFR * C *IN68 IFEQ *OFF C RTNCOD ANDEQ*OFF * : * : * {Perform some unique application function - here we will extract * the translated record returned and apply to our application.} C : C ENDIF C ENDDO * : * Close a request... * : C *IN68 IFEQ *OFF C RTNCOD ANDEQ*OFF C MOVE *BLANKS XA0020 C MOVEL'*CLOSE' FUNCTN C CALL 'XA0020R' 68 CLOSE STREAM FILE C PARM XA0020 C PARM RECBFR C ENDDO
LATEST COMMENTS
MC Press Online