Figure 3: Program IFS3CSV

     H DFTACTGRP(*NO)
     H OPTION(*SRCSTMT: *NODEBUGIO: *NOSHOWCPY)
     H BNDDIR('CSV')

     FMAILLIST  UF   E           K DISK

      /copy csv_h

     D ProcessRec      PR
     D   Rcd                               likeds(NCOAREC_t)
     D LoadFields      PR
     D   File                              likeds(CSVFILE_t)
     D   Rcd                               likeds(NCOAREC_t)
     D Crash           PR
     D   MsgTxt                    1000A   varying const

     D ncoa            ds                  likeds(CSVFILE_t)

     D NCOAREC_t       ds                  qualified
     D                                     based(Template)
     D  NameKey                      10A   varying
     D  DelCode                       1A   varying
     D  Match                         1A   varying
     D  Move                          1A   varying
     D  Date                          6A   varying
     D  Name                         25A   varying
     D  Company                      25A   varying
     D  Addr1                        30A   varying
     D  Addr2                        30A   varying
     D  City                         13A   varying
     D  State                         2A   varying
     D  Zip                           5A   varying
     D  NewAdd1                      30A   varying
     D  NewAdd2                      30A   varying
     D  NewCity                      13A   varying
     D  NewState                      2A   varying
     D  NewZip                        5A   varying
     D  NewZip4                       4A   varying
     D  RecordID                     10I 0

     D Rec             ds                  likeds(NCOAREC_T)
      /free

         // Read the NCOA file

         ncoa = CSV_open('/home/klemscot/NCOAbackto.CSV'
                        : *OMIT
                        : *OMIT );


         // Ignore the first record (it contains only column headings)

         CSV_loadrec(ncoa);

         // Read each record into the "Rec" data structure
         // and then process that record.

         dow CSV_loadrec(ncoa);
            LoadFields(ncoa: Rec);
            ProcessRec(Rec);
         enddo;

         CSV_close(ncoa);

         *inlr = *on;

      /end-free

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * LoadFields(): Load the CSV fields into a data structure
      *
      *    File = (i/o) CSV file that fields are to be read from
      *     Rcd = (output) Record to store results into
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P LoadFields      B
     D LoadFields      PI
     D   File                              likeds(CSVFILE_t)
     D   Rcd                               likeds(NCOAREC_t)

     D wwTemp          s             10A   varying

      /free
      
          CSV_getfld(File: Rcd.Namekey:  %size(Rcd.Namekey  ));
          CSV_getfld(File: Rcd.DelCode:  %size(Rcd.DelCode  ));
          CSV_getfld(File: Rcd.Match:    %size(Rcd.Match    ));
          CSV_getfld(File: Rcd.Move:     %size(Rcd.Move     ));
          CSV_getfld(File: Rcd.Date:     %size(Rcd.Date     ));
          CSV_getfld(File: Rcd.Name:     %size(Rcd.Name     ));
          CSV_getfld(File: Rcd.Company:  %size(Rcd.Company  ));
          CSV_getfld(File: Rcd.Addr1:    %size(Rcd.Addr1    ));
          CSV_getfld(File: Rcd.Addr2:    %size(Rcd.Addr2    ));
          CSV_getfld(File: Rcd.City:     %size(Rcd.City     ));
          CSV_getfld(File: Rcd.State:    %size(Rcd.State    ));
          CSV_getfld(File: Rcd.Zip:      %size(Rcd.Zip      ));
          CSV_getfld(File: Rcd.NewAdd1:  %size(Rcd.NewAdd1  ));
          CSV_getfld(File: Rcd.NewAdd2:  %size(Rcd.NewAdd2  ));
          CSV_getfld(File: Rcd.NewCity:  %size(Rcd.NewCity  ));
          CSV_getfld(File: Rcd.NewState: %size(Rcd.NewState ));
          CSV_getfld(File: Rcd.NewZip:   %size(Rcd.NewZip   ));
          CSV_getfld(File: Rcd.NewZip4:  %size(Rcd.NewZip4  ));
          CSV_getfld(File: wwTemp:       %size(wwTemp       ));

          monitor;
            Rcd.RecordID = %int(wwTemp);
          on-error;
            Rcd.RecordID = 0;
          endmon;
		
A
          
      /end-free
     P                 E

      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * ProcessRec(): process the data in one record from the file.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P ProcessRec      B
     D ProcessRec      PI
     D   Rcd                               likeds(NCOAREC_t)

      /free
      
         chain (Rcd.Namekey) MAILLIST;

         // -------------------------------------------
         //   When no record in our file matched,
         //   notify the user (this SHOULDN'T HAPPEN!)
         // -------------------------------------------
         select;
         when  not %found(MAILLIST);
            Crash('Unable to find a matching record for key '
                  + Rcd.NameKey + ' Record ID = '
                  + %char(Rec.RecordId) );

         // -------------------------------------------
         //   NIXIE record.
         //     Our policy when we get Nixies is to
         //     just leave the record as is.
         // -------------------------------------------
         when  Rec.DelCode = 'N';

         // -------------------------------------------
         //   Recipient moved; update database
         //    with recipient's new address.
         // -------------------------------------------
         when  Rec.DelCode = 'M';
            addr1 = rcd.newadd1;
            addr2 = rcd.newadd2;
            city  = rcd.newcity;
            state = rcd.newstate;
            zip   = rcd.newzip;
            zip4  = rcd.newzip4;
            update MAILLISTF;

         // -------------------------------------------
         //   Recipient moved, but no forwarding
         //    address is available.
         //
         //   Remove recipient from our mailing list.
         // -------------------------------------------
         other;
            delete MAILLISTF;
         endsl;
		
B
         
      /end-free
     P                 E


      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      * Crash(): Wrapper around the QMHSNDPM API to crash this
      *          program with an escape message.
      *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     P Crash           B
     D Crash           PI
     D   MsgTxt                    1000A   varying const

     D QMHSNDPM        PR                  ExtPgm('QMHSNDPM')
     D   MessageID                    7A   Const
     D   QualMsgF                    20A   Const
     D   MsgData                   1000A   Const
     D   MsgDtaLen                   10I 0 Const
     D   MsgType                     10A   Const
     D   CallStkEnt                  10A   Const
     D   CallStkCnt                  10I 0 Const
     D   MessageKey                   4A
     D   ErrorCode                 1024A   options(*varsize)

     D ErrorNull       DS
     D  BytesProv                    10I 0 inz(0)
     D  BytesAvail                   10I 0 inz(0)

     D MsgKey          S              4A
      /free
           QMHSNDPM( 'CPF9897'
                   : 'QCPFMSG   *LIBL'
                   : MsgTxt
                   : %len(MsgTxt)
                   : '*ESCAPE'
                   : '*PGMBDY'
                   : 1
                   : MsgKey
                   : ErrorNull );
      /end-free
     P                 E