U bent hier

Write correct UTF-8 directly to IFS from RPGLE

First you need, of course, some declarations of structures and procedures

     D iConvStruc      DS                  qualified
     D                                     based(#)
     D   result                      10I 0
     D   cd                          10I 0 dim(12)

     D iConvCode       DS                  qualified
     D  CCSID                        10I 0 inz
     D  ConvAlt                      10I 0 inz
     D  SubsAlt                      10I 0 inz
     D  ShiftAlt                     10I 0 inz
     D  InpLenOp                     10I 0 inz
     D  ErrorOpt                     10I 0 inz
     D  Reserved                      8A   inz(*ALLx'00')

     D iconvSource     ds                  likeds(iConvCode)
     D                                     inz(*likeds)
     D iconvTarget     ds                  likeds(iConvCode)
     D                                     inz(*likeds)
     D toUTF8          ds                  likeds(iConvStruc)

     D iconvOpen       PR                  extproc('QtqIconvOpen')
     D                                     like(iConvStruc)
     D    toCode                           likeds(iConvCode) const
     D    fromCode                         likeds(iConvCode) const

     D iconv           PR            10U 0 extproc('iconv')
     D   cd                                like(iConvStruc) value
     D   inbuf                         *
     D   inbytesleft                 10U 0
     D   outbuf                        *
     D   outbytesleft                10U 0

     D iconvClose      PR            10I 0 extproc('iconv_close')
     D   cd                                like(iConvStruc) value

Before doing the first conversion of data, you need initialization of a 'ebcdic-to-utf8-block':

       iconvSource.CCSID = 0; // 0 = job's ccsid
       iconvTarget.CCSID = 1208; // 1208 = UTf-8
       toUTF8 = iconvOpen( iconvTarget: iconvSource );
       if (toUTF8.result = -1);
         die('iconvOpen(): ' + %str(strerror(errno)));

When creating a file, make sure it is created with CCSID 1208:

(the output of the byte-order-mark EF BB BF in the code below is not really required, but if you are writing, for example, a csv which is to be opened by MS-Excel: then you want to add this, because microsoft expects this non-standard BOM to recognize the UTF8)

     P ifsOpen         B
     D ifsOpen         pi            10i 0
     D  pFileName                      *   Value
     DaFileDescriptor  s             10i 0
     DaByteOrderMark   s              3a   inz(x'EFBBBF')
       if (uxAccess(pFileName:0)0);
         aFileDescriptor=uxOpen( pFileName
                               : O_WRONLY+O_CREAT+O_TRUNC+O_CCSID
                               : S_777   //(yeah, whatever for the demo)
                               : 1208
         if (aFileDescriptor=-1);
           die('uxOpen(): ' + %str(strerror(errno)));
         uxClose( aFileDescriptor );
       return uxOpen( pFileName
                    : S_777   //(yeah, whatever for the demo)
                    : 1208
     P                 E

So, when the file is open and writeable, make sure that every write to that file is accompanied with a ebcdic-to-utf8-conversion:

     P iifsWrite       B
     D iifsWrite       pi              *
     D  pFileDescriptor...
     D                               10i 0 Value
     D  pStringAddr                    *   Value
     D  pStringSize                  10u 0 Value
     DaInputPtr        s               *
     DaOutputPtr       s               *
     D                 s               *
     DaInputSize       s             10u 0
     DaOutputSize      s             10u 0
     D                 s             10u 0
     D                 s             10u 0
     DaResult          s               *
       aOriginalOutputStringSize=aInputSize*2; // x2:Just a choice
       iconv( toUTF8
            : aInputPtr
            : aInputSize
            : aOutputPtrDisposable
            : aOutputSize );
       aOutputStringSize = aOriginalOutputStringSize - aOutputSize;
       dealloc aOutputPtr;
       return aResult;
     P                 E

When you're done converting, clean up the converison


Some code you might want as sample if you want to start using code above...

      // oflag
     D O_RDONLY        C                   1                                    Read only
     D O_WRONLY        C                   2                                    Write only
     D O_RDWR          C                   4                                    Read/Write
     D O_CREAT         C                   8                                    ¬Create|
     D O_EXCL          C                   16                                   Create
     D O_CCSID         C                   32                                   CCSID
     D O_TRUNC         C                   64                                   Truncate
     D O_APPEND        C                   256                                  Append
     D O_CODEPAGE      C                   8388608                              Convert
     D O_TEXTDATA      C                   16777216                             Open in textmode
      // mode
     D S_IRUSR         C                   256
     D S_IWUSR         C                   128
     D S_IXUSR         C                    64
     D S_IRWXU         C                   448
     D S_IRGRP         C                    32
     D S_IWGRP         C                    16
     D S_IXGRP         C                     8
     D S_IRWXG         C                    56
     D S_IROTH         C                     4
     D S_IWOTH         C                     2
     D S_IXOTH         C                     1
     D S_IRWXO         C                     7
     D S_777           C                   511

      // 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')

(Also used https://www.scottklement.com/rpg/ifs_ebook/index.html as reference during writing this code)

IT area: