Carlos, hace algun tiempo Alex publico en recursos un documento en donde
explica como crear archivos de PC desde RPG IV:

http://www.recursos-as400.com/como67.shtml

Igualmente en su momento, Alex me envio un articulo que me fue de gran
utilidad para comprender algunas cosas, te lo copio a continuacion:

_____________________________________________________________________________
RPG IV and the IFS
by Ted Holt

You don't have to get a C compiler to write programs that access the
Integrated File System (IFS) and the Novell Network File System (NFS). RPG
IV programs can bind to the same APIs that C uses. You can read and write
IFS files, and it's probably easier than you think!

I attended some very interesting sessions at COMMON in San Antonio this
past September, among them Ray Bills' session, "Access the Integrated File
System from RPG." For some time, I had wanted to write RPG programs that
would directly read from and write to the IFS, but I had assumed it wasn't
yet possible--or at least not feasible.

Boy, was I wrong! Not only is it possible, it's (relatively) easy!

Ray, who works for IBM Rochester, had thought the same, until Massimo
Marasco of IBM Italy contacted him for some debugging help. Ray asked
Massimo to send him a copy of his C source, and Massimo replied that his
program was written in RPG, not C. A new world opened to Ray, and he was
kind enough to share it with us at COMMON.

So, I stand on the shoulders of giants. Having attempted to give credit
where it is due, I move to the subject at hand.

What Is the IFS?
Most computers have one way of storing programs and data. On PCs and UNIX
systems, for example, we store everything in files, which we organize into
directories. On the AS/400, we store most types of objects (e.g., database
files, programs, data areas, and data queues) in libraries. We store
certain other types, like documents and PC files, in a hierarchical filing
system of folders. These typical AS/400 filing systems work well for the
data processing and office functions AS/400 users have traditionally
needed, but they don't work well for all the types of data modern computers
are being asked to store. IBM created the Integrated File System (IFS) as a
way of allowing more filing systems to exist on the AS/400 so that we would
be able to put any type of object into the AS/400's disk storage. To learn
more about the IFS, see "V3R1 Announcement Follow-up: The Integrated File
System," MC, July 1994.

So if you need a PC-type filing system on the AS/400, you've got it. If you
need a secure server for your LAN, it's there. If you need to store graphic
images (TIFF, BMP, etc.), multimedia presentations, and such on your
AS/400, the IFS is ready for the task.

Many AS/400 shops have not taken advantage of the IFS. For the most part,
they don't need it. Database is still the lifeblood of businesses, and
databases are still stored in libraries. Another reason people haven't used
the IFS is that it is not directly addressable from RPG programs. That is,
you can't declare an IFS file in an F-spec. Instead, you have to use
something like C or Perl. However, with a client like the Windows 95
Explorer, you can access an IFS file.

One of the beauties of the AS/400, and especially ILE, is that if one
language can do something, all of them can (to a degree, at least.) Since C
can access the IFS, so can RPG. The APIs C uses are described in the OS/400
UNIX-type APIs manual (see the references at the end of this article). Now,
I'm going to give you two example RPG programs that access the IFS: one to
read from the IFS, the other to write to it. I have tried to keep these
very short and simple so you can concentrate on understanding how this
works. You can find more examples, in C, COBOL, and RPG, in Appendix B of
the System API Programming manual.

Reading from the IFS
Before you can read from a file, you have to open it. The UNIX-type API
that opens files, believe it or not, is named open(). To read data from an
IFS file, use the read() API. When you're finished with the file, close()
it.

You can call these APIs using the callp (Call a Prototyped Procedure or
Program) op code, but since they return a value, you really should use them
the way you use built-in functions, like %SUBST and %TRIM. That is, you'll
use them in Eval statements.

In any event, you'll have to prototype them in your RPG programs. IBM
supplies header files that include the C prototypes, but it hasn't yet
released copybooks with RPG prototypes. You can look up the function
definitions in the API manual or look at the appropriate header file in the
QSYSINC library. Or you can just use the IFSPROTOS member in Figure 1.

I got some of this from Ray Bills, and I added other things myself as I
needed to. It's not complete, so you may have to add more to it. The
UNIX-type APIs manual will tell you which header file contains a function's
prototype and show you how the function is defined. You can look at the
header file in library QSYSINC for more information. Be aware that any
constant that begins with a zero (but not a zero followed by an X) is an
octal number, not a decimal number.

Once you've got this copybook on your system, you'll just need to /COPY it
into your programs that use the IFS, as I have done in the programs in
Figures 2 and 3.

Now, look at the RPG program in Figure 2. It opens an ASCII text file of
variable length records and prints them to QSYSPRT. I created the ASCII
file on my PC using a spreadsheet, saved it in comma-delimited format, and
FTPed it to my play directory on MC's RISC machine. The AS/400 created the
file in the IFS with code page 819, one of the ASCII code pages.

The first D-spec copies the prototypes and constants the APIs need. The
rest of the D-specs define constants and working variables. You might want
to add some of these constants to the IFSPROTOS member so you wouldn't have
to define them in the programs that need them. Now, look at the C-specs. To
open the file, I call the open() API. This API needs to know what file I
want to open and how I want to open it.

To tell it the name of the file to open, I have to pass it a pointer to
(the address of) a null-terminated string. The first Eval strips leading
and trailing blanks from the file name and appends a null. The second Eval
sets the open flag to the attributes read-only and text-data. (These
attributes are defined in IFSPROTOS.) "Read-only" means I'm opening it for
input, of course. "Text-only" means that the file is a text file, not a
binary file. This causes the system to translate the data to the CCSID of
the job. In this case, the ASCII data gets translated to EBCDIC.

The result of the open(), the value it returns, is assigned to the variable
fp. If the open() fails, it returns a negative number, and I can take
appropriate action. If it succeeds, it gives me a file pointer number that
I refer to when I read the file.

Once the file is open, I can read it. Variable-length records are separated
by the carriage return-line feed combination, which comes into this program
as X'0D25'. Since I don't know how long each record will be, I read the
file a character at a time, building a record until I hit a carriage
return. I ignore line feed characters.

Look at the GetChar subroutine. It first checks to see if all characters
previously read have been processed. (This will prove true the first time
through, as zero characters have been processed, and zero characters were
last read.) If so, it blanks the input variable, calls the read() API to
get another block of 256 characters, and resets the index into the input
variable.

The read() API requires three pieces of information: the file pointer
returned by open() so it knows which file to read, the address of the
variable into which to store the retrieved data, and the number of bytes of
data it should read. It will return the number of bytes read. A positive
number means it retrieved data. Zero means there was no more data to read.
A negative number indicates that an error occurred on the read.

I told it to get 256 bytes of data at a time. It will get as many as it
can. If there are 259 bytes of data in the file, it will get 256 the first
time, 3 the second time, and zero the third time.

The GetChar subroutine continues by extracting the next character from the
buffer into CurChar (current character) so the main routine can process it.

When the main routine finds a carriage return, it prints a line. It ignores
line feed characters. It copies anything else into the next position of the
output buffer.

Eventually, this program runs out of data, and I'm ready to close the file.
The close() function also returns a value, so I should use Eval to assign
the function result to a return code. However, I wanted to show you that
you can use a callp op code to run these functions if you want to. The RPG
compiler generates an RNF5409 error ("The prototyped call returns a value
which is lost when CALLP is used"). In other words, you can ignore the
return value if you want to.

Take a look at the compilation instructions at the top of the program. You
have to include the QC2LE binding directory so the system can find these
APIs during program creation. This program is not robust. For example, it
assumes that no input record will have more than 80 characters of data in
it. My first inclination was to reprint the CSV001RG program I published
last February, making it read from the IFS. (See "Extracting Problem Data
from PC Files," MC, February 1997.) That would have been more realistic,
but much too long for publication. So I opted for this short example
instead. I hope you can integrate the portions of this code that you need
into your applications.

Writing to the IFS
The program in Figure 3 reads data from a physical file and writes it, in
comma-delimited format, to an IFS file. Let's see how it works.

The D-specs are more or less like those in Figure 2. Let's start with the
C-specs. The first step is to create the file in the IFS. The creat() API
creates a new file, but I'm going to use open() instead, because, as Ray
Bills showed me, open() allows me to specify a code page, but creat() does
not. Since FTP creates the files I transfer to the AS/400 with code page
819, I decided to use code page 819 for this example as well. Keep in mind
that code page 819 is an ASCII code page, not EBCDIC.

The first Eval sets the attributes for the open. In this case, the
attributes say that I am creating a file, that I am specifying a code page
parameter on the open, and that the file is to have read-write attributes.

The second Eval sets the proper value for the authority to the file, which
is expressed in the mode parameter. The value S_IRWXU says the owner is
allowed *RWX (read-write-execute) authorities, and S_IROTH means *PUBLIC is
allowed only to read it.

The third Eval builds a null-terminated string of the file name.

The fourth Eval executes the open() function to create the file. The open
function has four arguments here: the address of (a pointer to) the file
name, the attributes in the oflag, the authorities, and the code page to be
used. It returns a value to the fp variable. If the open fails, this value
will be negative, and I can do some appropriate error processing.

If all went well, the file is open, but not for translation between code
pages. To make the system translate data from one code page to another, I
have to close the file and open it again. Before executing the second open
(), I set the attributes to write-only and tell it to translate from the
job's code page (EBCDIC) to the IFS file's code page (ASCII).

To summarize, the file needs to be opened twice-the first time to create
the file, the second time to force data translation as the program writes
to the files.

Now that the IFS file is open, I need to load it with data. I start a loop
that reads database file StoreData and writes each record, in
comma-delimited format, to the IFS file. The first Eval inside the loop
builds the comma-delimited variable, and the second Eval writes it.
(Perhaps you're wondering what happens if, in building this variable, you
concatenate an alphanumeric field that contains an embedded comma. Embedded
commas are OK inside quoted strings. Embedded quotes, however, should be
doubled-but I don't do that in this example.) This is generally not a
robust way to build a comma-delimited file, because it doesn't double
quotation marks inside character values. It is adequate for this
illustration, because the input data does not contain quotation marks.

Notice the write() function. The arguments are the file pointer returned by
open(), the address of the data being written, and the number of bytes to
be written. The function returns the number of bytes it writes into
variable rc. I don't check for an error here, but I could easily do so by
making sure rc has a positive value after the write() executed. Ideally, rc
should return the same value as the write function's third parameter.

When I'm finished copying the data, I close the file. Notice I used Eval,
not callp, this time. Again, I don't check for an error, but if the close
doesn't work correctly, rc will be negative.

Potential for Service
I've been discussing the IFS, but these APIs work with the NFS as well. I
haven't tried this yet, but I'm told that you can use these APIs to read
and write to other devices on a network. For example, a user might use a
spreadsheet or database to build a CSV file every day on his PC's hard
drive. At night, the AS/400 could read that file directly from his PC,
process it, and create a new file on his hard drive that he could open and
begin to work with the next morning. All of this would take place without
file transfer.

It seems to me, then, that these APIs give us more or better ways to serve
the people who use our AS/400s. I've enjoyed learning how to use these
APIs, and plan to use them soon in production work for my consulting firm.
I hope you find a lot of good uses for these APIs too.

Ted Holt is a technical editor for Midrange Computing and a consultant
living in Corinth, Mississippi. You can contact him by email at
[EMAIL PROTECTED]

REFERENCES AND RELATED MATERIALS
OS/400 UNIX-type APIs (SC41-4875, CD-ROM QBKAM401)
System API Programming (SC41-4800, CD-ROM QBKAVC00)

FIGURE 1: This RPG copybook contains some of the prototypes and data
declarations the UNIX-type APIs need.

.BOF----
* Prototypes and definitions for working with the IFS
       *
       * Warning: this file may be incomplete or contain errors!
       *
       *  open -- open an IFS file
       *
      D open            pr            10i 0   ExtProc('open')
      D   filename                      *     value
      D   openflags                   10i 0   value
      D   mode                        10u 0   value options(*nopass)
      D   codepage                    10u 0   value options(*nopass)
       * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
       *  read -- read an IFS file
       *
      D read            pr            10i 0   ExtProc('read')
      D   filehandle                  10i 0   value
      D   datareceived                  *     value
      D   nbytes                      10u 0   value
       * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
       *  write -- write to an IFS file
       *
      D write           pr            10i 0   ExtProc('write')
      D   filehandle                  10i 0   value
      D   datatowrite                   *     value
      D   nbytes                      10u 0   value
       * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
       *  close- close an IFS file
       *
      D close           pr            10i 0   ExtProc('close')
      D   filehandle                  10i 0   value
       * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
       * values for oflag parameter, used by open()
       * from QSYSINC/H, member FCNTL
      D O_APPEND        s             10i 0   inz(256)
      D O_CODEPAGE      s             10i 0   inz(8388608)
      D O_CREAT         s             10i 0   inz(8)
      D O_EXCL          s             10i 0   inz(16)
      D O_RDONLY        s             10i 0   inz(1)
      D O_RDWR          s             10i 0   inz(4)
      D O_TEXTDATA      s             10i 0   inz(16777216)
      D O_TRUNC         s             10i 0   inz(64)
      D O_WRONLY        s             10i 0   inz(2)

       * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
       * user authorities for omode parameter, used by open()
       * from QSYSINC/SYS, member STAT
      D S_IRUSR         s             10i 0   inz(256)
      D S_IWUSR         s             10i 0   inz(128)
      D S_IXUSR         s             10i 0   inz( 64)
      D S_IRWXU         s             10i 0   inz(448)
       * group authorities
      D S_IRGRP         s             10i 0   inz( 32)
      D S_IWGRP         s             10i 0   inz( 16)
      D S_IXGRP         s             10i 0   inz(  8)
      D S_IRWXG         s             10i 0   inz( 56)
       * other authorities
      D S_IROTH         s             10i 0   inz(  4)
      D S_IWOTH         s             10i 0   inz(  2)
      D S_IXOTH         s             10i 0   inz(  1)
      D S_IRWXO         s             10i 0   inz(  7)

.EOF---

FIGURE 2: This RPG program reads ASCII data from the IFS and prints it.

.BOF---
* =============================================================== *
       * Read data from the Integrated File System                       *
       * =============================================================== *
       * To compile:                                                     *
       *                                                                 *
       *    CRTBNDRPG  PGM(XXX/CSV002RG) DFTACTGRP(*NO) BNDDIR(QC2LE)    *
       *                                                                 *
       * =============================================================== *

      Fqsysprt   o    f  132        printer     oflind(*inof)

      D/copy xxx/qrpglesrc,ifsprotos
      D CharsRead       s             10i 0
      D CurChar         s              1
      D CR              c                   const(x'0D')
      D EOF             c                   const(x'00')
      D LF              c                   const(x'25')
      D NULL            c                   const(x'00')
      D FileName        s             80    inz('/home/holt/store2.csv')
      D fp              s             10i 0
      D Input           s            256
      D ix              s              5  0
      D LogicalRec      s             80
      D oflag           s             10i 0
      D ox              s              5  0

       * Open the IFS file.
      C                   eval      FileName = %trim(FileName) + NULL
      C                   eval      oflag = O_RDONLY + O_TEXTDATA
      C                   eval      fp = open(%addr(FileName): oflag)
      C                   if        fp < 0
       * The following line should do an error routine.
      C                   except    openerror
      C                   endif

      C                   exsr      GetChar
      C                   dow       CurChar <> EOF
      C                   select
      C                   when      CurChar = CR
      C                   except    dtl
      C                   eval      ox = *zero
      C                   eval      LogicalRec = *blanks
      C                   when      CurChar = LF
       *                  ignore line feed
      C                   other
      C                   eval      ox = ox + 1
      C                   eval      %subst(LogicalRec: ox: 1) = CurChar
      C                   endsl
      C                   exsr      GetChar
      C                   enddo

      C                   CallP     close(fp)
      C                   eval      *inLR = *on
       *******************
      C     GetChar       begsr

       *        If input buffer is empty, or all characters have been
       *          processed, refill the input buffer.

      C                   if        ix = CharsRead
      C                   eval      Input = *blanks
      C                   eval      CharsRead  = read(fp: %addr(Input):
256)
      C                   eval      ix = *zero
      C                   endif

       *        Get the next character in the input buffer.

      C                   if        CharsRead <= 0
      C                   eval      CurChar = EOF
      C                   else
      C                   eval      ix = ix + 1
      C                   eval      CurChar = %subst(Input: ix: 1)
      C                   endif
      C
      C                   endsr

      Oqsysprt   e            dtl            1
      O                                              '('
      O                       LogicalRec
      O                                              ')#'
      Oqsysprt   e            openerror      1
      O                                              'open error fp('
      O                       fp
      O                                              ')'

.EOF---


FIGURE 3: This program builds an ASCII CSV file from a database file.

.BOF---
* =============================================================== *
       * Write data to the Integrated File System                        *
       * =============================================================== *
       * To compile:                                                     *
       *                                                                 *
       *    CRTBNDRPG  PGM(XXX/CSV003RG) DFTACTGRP(*NO) BNDDIR(QC2LE)    *
       *                                                                 *
       * =============================================================== *

      FStoreData if   e           k disk

      D/copy xxx/qrpglesrc,ifsprotos
      D CodePage        s             10u 0 inz(819)
      D Comma           c                   const(',')
      D NULL            c                   const(x'00')
      D EndOfData       s              1
      D EOL             c                   const(x'0d25')
      D FileName        s             80    inz('/home/holt/storedta.csv')
      D fp              s             10i 0
      D oflag           s             10i 0
      D omode           s             10u 0
      D OutRec          s            256
      D Quote           c                   const('"')
      D rc              s             10i 0

       * Create the IFS file.
      C                   eval      oflag = O_CREAT + O_CODEPAGE + O_RDWR
      C                   eval      omode = S_IRWXU + S_IROTH
      C                   eval      FileName = %trim(FileName) + NULL
      C                   eval      fp = open(%addr(FileName): oflag:
      C                                       omode: CodePage)
      C                   if        fp < 0
       * Insert error handler here.
      C                   endif

       * Close the file so we can reopen it for output with translation
      C                   eval      rc = close(fp)

       * Open the IFS file for output.
      C                   eval      oflag = O_WRONLY + O_TEXTDATA
      C                   eval      fp = open(%addr(FileName): oflag)
      C                   if        fp < 0
       * Insert error handler here.
      C                   endif

      C                   read      StoreRec
51
      C                   eval      EndOfData = *in51
      C                   dow       EndOfData = '0'
      C                   eval      OutRec = Quote + %trim(StoreID) +
      C                              Quote + Comma +
      C                              %triml(%editc(CYMTD: 'P')) + Comma +
      C                              %triml(%editc(CYYTD: 'P')) + EOL
      C                   eval      rc = write(fp: %addr(OutRec):
      C                                  %len(%trimr(OutRec)))
      C                   read      StoreRec
51
      C                   eval      EndOfData = *in51
      C                   enddo

       * Close the IFS file.
      C                   eval      rc = close(fp)
      C                   eval      *inLR = *on
.EOF---

_____________________________________________________________________________



Saludos.

Jes�s Humberto Olague Alcal�
L�der de Proyectos
Envases y Tapas Modelo, S.A. de C.V.
e-mail: [EMAIL PROTECTED]
Tel:  (478) 985 4100 Ext. 247
Fax: (478) 985 4100 Ext. 249


_____________________________________________________
Forum.HELP400 es un servicio m�s de NEWS/400.
� Publicaciones Help400, S.L. - Todos los derechos reservados
http://www.help400.es
_____________________________________________________

Para darte de baja, env�a el mensaje resultante de pulsar
mailto:[EMAIL PROTECTED]

Responder a