U bent hier

Use an internal buffer for writing groups of lines to an IFS file in RPGLE

The H-line requires QC2LE, because we will be using C functions, among other...

H bnddir('QC2LE')

Prototypes

As mentioned, some Unix & C functions for accessing IFS files, and for copying memory blocks:
Notice that below there is an ifsWrite and an iifsWrite ("Internal-ifsWrite"): ifsWrite is used by the application code lines, while iifsWrite is used by ifsWrite to do the actual writing to the IFS file

     DCarriageReturn   c                   const(x'0D')

     D memcpy          PR            10I 0 ExtProc('memcpy')
     D  dest                           *   Value OPTIONS(*STRING)
     D  source                         *   Value OPTIONS(*STRING)
     D  count                        10I 0 Value
     D memchr          PR              *   ExtProc('memchr')
     D  buf                            *   Value OPTIONS(*STRING)
     D  c                            10I 0 Value
     D  count                        10I 0 Value

     D ifsAccess       PR            10I 0 extproc('access')
     D  Pathptr1                       *   value
     D  Mode1                        10I 0 value
     D ifsOpen         pr            10i 0
     D  pFileName                      *   Value
     D ifsWrite        pr
     D  pStringAddr                    *   Value
     D  pStringLength                10i 0 Value
     D  pFileDescriptor...
     D                               10i 0 Value
     D  pJournaled                     n   Const Options(*omit:*nopass)
     D iifsWrite       pr              *
     D  pFileDescriptor...
     D                               10i 0 Value
     D  pStringAddr                    *   Value
     D  pStringSize                  10u 0 Value
     D ifsFlush        pr              n
     D  pCommit                        n
     D ifsCopy         pr
     D  pObject                    4096a   Value
     D  pToDir                     4096a   Value

      // Unix file functions
     D uxAccess        PR            10I 0 extproc('access')
     D  Pathptr1                       *   value
     D  Mode1                        10I 0 value
     D uxOpen          PR            10I 0 extproc('open')
     D  path                           *   value options(*string)
     D  oflag                        10I 0 value
     D  mode                         10U 0 value options(*nopass)
     D  codepage                     10U 0 value options(*nopass)
     D uxWrite         pr              *   ExtProc('write')
     D  pFileDescriptor...
     D                               10i 0 Value
     D  pStringAddr                    *   Value
     D  pStringSize                  10u 0 Value
     D uxClose         PR            10I 0 extproc('close')
     D   pFileDescriptor...
     D                               10I 0 value
     D strerror        PR              *   ExtProc('strerror')
     D    errnum                     10I 0 value
     D @__errno        PR              *   ExtProc('__errno')

A procedure's prototype ifsFlush; to flush the data to the actual IFS file:

D ifsFlush        pr
D pCommit                         n

Usage of the procedures

When the program does DB2 and IFS output, it uses the procedure ifsWrite to 'write' data to an IFS file, the IFS file is previously opened with ifsOpen which returned a handle, gFileHandle:

/Free
           aOutputLine = %Trim(aOutputLine) + CarriageReturn;
           ifsWrite( %Addr(aOutputLine)
                   : %Len(%TrimR(aOutputLine))
                   : aFileDescriptor);
/End-Free

And when the program decides a commit or a rollback, it can do a flush with the ifsFlush procedure (implementation of this procedure: see below):

/Free
 Commit;
 ifsFlush(true);
/End-Free

or

/Free
 Rolbk;
 ifsFlush(false);
/End-Free

Implementations

     P ifsWrite        B
     D ifsWrite        pi
     D  pStringAddr                    *   Value
     D  pStringLength                10i 0 Value
     D  pFileDescriptor...
     D                               10i 0 Value
     D  pJournaled                     n   Const Options(*omit:*nopass)
     D aJournaled      s               n
     D aNewAlloc       s               *
      /Free
       if (%Parms()>3) and (%Addr(pJournaled)*null);
         aJournaled=pJournaled;
       else;
         aJournaled=true;
       endif;
       if (aJournaled);
         aNewAlloc=%Alloc(%Size(gifsPendingFileBuffer));
         if (gifsPendingFileBufferRootPointer=*null);
           gifsPendingFileBufferRootPointer=aNewAlloc;
         else;
           gifsPendingFileBuffer.PendingFileBufferNextPointer=aNewAlloc;
         endif;
         gifsPendingFileBufferCurrentPointer=aNewAlloc;
         gifsPendingFileBuffer.RecordFileDescriptor=pFileDescriptor;
         gifsPendingFileBuffer.RecordPointer=%Alloc(pStringLength);
         gifsPendingFileBuffer.RecordSize=pStringLength;
         memcpy(gifsPendingFileBuffer.RecordPointer:pStringAddr:pStringLength);
         gifsPendingFileBuffer.PendingFileBufferNextPointer=*null;
       else;
         iifsWrite(pFileDescriptor:pStringAddr:pStringLength);
       endif;
      /End-Free
     P ifsWrite        E


     P ifsFlush        B
     D ifsFlush        pi              n
     D  pCommit                        n
     d aToDeAlloc      s               *
      /Free
       gifsPendingFileBufferCurrentPointer=
          gifsPendingFileBufferRootPointer;
       DoW (gifsPendingFileBufferCurrentPointer*null);
         if (pCommit); // flush into endless universe if no commit required
           iifsWrite(gifsPendingFileBuffer.RecordFileDescriptor
                    :gifsPendingFileBuffer.RecordPointer
                    :gifsPendingFileBuffer.RecordSize);
         endif;
         dealloc gifsPendingFileBuffer.RecordPointer;
         aToDeAlloc = gifsPendingFileBufferCurrentPointer;
         gifsPendingFileBufferCurrentPointer=
           gifsPendingFileBuffer.PendingFileBufferNextPointer;
         dealloc aToDeAlloc;
       EndDo;
       gifsPendingFileBufferRootPointer=*null;
       return pCommit;
      /End-Free
     P ifsFlush        E

Pointer structure definitions

You have noticed the pointer variables above. This is the definition of it:

     D gifsPendingFileBufferRootPointer...
     D                 s               *
     D gifsPendingFileBufferCurrentPointer...
     D                 s               *
     D gifsPendingFileBuffer...
     D                 DS                  Qualified
     D                                     Based(
     D                                      gifsPendingFileBufferCurrentPointer)
     D   RecordFileDescriptor...
     D                               10i 0
     D   RecordPointer...
     D                                 *
     D   RecordSize...
     D                               10i 0
     D   PendingFileBufferNextPointer...
     D                                 *

Don't forget to initialize the two global variables before starting to work with them

/Free
  gifsPendingFileBufferRootPointer=*null;
  gifsPendingFileBufferCurrentPointer=*null;
/End-Free
IT area: