Figure 2: Service program CSVR4

     H NOMAIN
     H OPTION(*SRCSTMT: *NOSHOWCPY)
     H BNDDIR('QC2LE')

      /copy bufio_h
      /copy csv_h

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * CSV_open(): open a delimited text file
      *
      *    peFilename = (input) IFS pathname of file to open
      *      peStrDel = (input/omit) String delimiter
      *                  if *OMIT, a double-quote character is used
      *      peFldDel = (input/omit) Field delimiter
      *                  if *OMIT, a comma is used
      *
      * returns a CSVFILE_t data structure
      *        or an *ESCAPE message upon error
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P CSV_open        B                   export
     D CSV_open        PI                  likeds(CSVFILE_t)
     D   peFilename                1024A   varying const
     D                                     options(*varsize)
     D   peStrDel                     1A   const options(*omit)
     D   peFldDel                     1A   const options(*omit)

     D myCSV           ds                  likeds(CSVFILE_t)
     D                                     inz(*LIKEDS)

      /free

         if (%addr(peStrDel) <> *NULL);
            myCSV.StrDel = peStrDel;
         endif;

         if (%addr(peFldDel) <> *NULL);
            myCSV.FldDel = peFldDel;
         endif;
   
         myCSV.fp = fopen(peFilename: 'r');

         if (myCSV.fp = *NULL);
            ReportError();
         endif;
         		
A

         myCSV.buf = '';
         myCSV.bufpos = 1;

         return myCSV;

      /end-free
     P                 E

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * CSV_loadrec(): Load a record from a delimited file into memory
      *
      *     peCSV = (i/o) CSVFILE_t DS returned by CSV_open()
      *
      * Returns *ON if successful, *OFF upon failure or EOF
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P CSV_loadrec     B                   export
     D CSV_loadrec     PI             1N
     D   peCSV                             likeds(CSVFILE_t)

     D buf             s          32767A
     D p_buf           s               *
     D len             s             10I 0

      /free

         p_buf = fgets(%addr(buf): %size(buf): peCSV.fp);

         if (p_buf = *NULL);
            return *OFF;
         endif;

         peCSV.buf = %str(p_buf);

         len = %len(peCSV.buf);
         		
B

         if (%suzbst(peCSV.buf : len : 1) = x'25');
            len = len - 1;
            %len(peCSV.buf) = len;
         endif;

         if (%subst(peCSV.buf : len : 1) = x'0D');
            len = len - 1;
            %len(peCSV.buf) = len;
         endif;
		
C
         

         peCSV.bufpos = 1;

         return *ON;
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * CSV_getfld(): Get the next field from a delimited file record
      *
      *     peCSV = (i/o) CSVFILE_t DS returned by CSV_open()
      * peFldData = (output) data read from file
      * peVarSize = (input) size, in bytes, of the peFldData
      *                     variable that you passed (including
      *                     the two bytes for the length)
      *
      * Returns *ON if data was read, *OFF otherwise
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P CSV_getfld      B                   export
     D CSV_getfld      PI             1N
     D   peCSV                             likeds(CSVFILE_t)
     D   peFldData                32767A   varying options(*varsize)
     D   peVarSize                   10I 0 value

     D max             s             10I 0
     D len             s             10I 0
     D start           s             10I 0
     D pos             s             10I 0
     D retval          s              1N
     D inString        s              1N
     D char            s              1A

      /free

         max = peVarSize - 2;
         len = %len(peCSV.buf);
         start = peCSV.bufpos;
         retval = *OFF;
         %len(peFldData) = 0;

         for pos = start to len;

             char = %subst(peCSV.buf: pos: 1);

             select;
             when (inString and char = peCSV.strdel);
                 inString = *OFF;
             when (not inString and char = peCSV.flddel);
                 peCSV.bufpos = pos + 1;
                 leave;
             when (not inString and char = peCSV.strdel);
                 inString = *ON;
             when (%len(peFldData) < max);
                 retval = *ON;
                 peFldData = peFldData + char;
             endsl;

         endfor;
		
D

         return retval;
      /end-free
     P                 E

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * CSV_close(): Close. 
      *
      *     peCSV = (i/o) CSVFILE_t DS returned by CSV_open()
      *
      * Returns the field value
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P CSV_close       B                   export
     D CSV_close       PI
     D   peCSV                             likeds(CSVFILE_t)

      /free

         if (fclose(peCSV.fp) <> 0);
            ReportError();
         endif;
		
		
E
      /end-free
     P                 E