7.6. Reading Directories

Once the directory has been opened, we will want to read it's contents. This is accomplished using the readdir() "Read Directory" API.

Here is the C language prototype for the readdir() API:

      struct dirent *readdir(DIR *dirp) 
   

The return value of readdir() is a pointer that points to a data structure in the "dirent" format. Back in the discussion of the stat() API, I explained that in C, you first define a data structure's format, and then you define structures that use that format. In this case, the format is called "dirent".

We will need to know how to define our own dirent data structures, since that's where the useful information from the directory comes from. However, for creating the RPG prototype, we really only needed to know that the return value is a pointer. So, here's the RPG prototype:

     D readdir         PR              *   EXTPROC('readdir')   
     D  dirp                           *   VALUE                
   

To get useful information out of this API, as I mentioned above, we need to make our own dirent structure. The definition of this structure in C looks like this;

     struct dirent {                                                        
       (1)char           d_reserved1[16];  /* Reserved                       */
       (2)unsigned int   d_fileno_gen_id;  /* File number generation ID  @A1C*/
       (3)ino_t          d_fileno;         /* The file number of the file    */
       (4)unsigned int   d_reclen;         /* Length of this directory entry   
                                           in bytes                       */
       (5)int            d_reserved3;      /* Reserved                       */
       (6)char           d_reserved4[8];   /* Reserved                       */
       (7)qlg_nls_t      d_nlsinfo;        /* National Language Information    
                                           about d_name                   */
       (8)unsigned int   d_namelen;        /* Length of the name, in bytes     
                                           excluding NULL terminator      */
       (9)char           d_name[_QP0L_DIR_NAME]; /* Name...null terminated   */
     };                                                                     
   
(1)
The first subfield in the dirent data structure is simple. It's a 16-byte long character field marked as "reserved".
(2)
Next, we have the file number generation ID. It's marked as an unsigned integer, which is equivalent to the RPG "10U 0" data type. This field probably won't be useful to you as an RPG programmer, so I won't explain what it contains.
(3)
The file number is defined as a "ino_t". If we hunt through the C header members, we will find that ino_t is defined in the file QSYSINC/SYS,TYPES as an unsigned integer. Good, that's an RPG "10U 0". Again, this field isn't likely to be useful to an RPG programmer, so I won't explain it.
(4)
The length of the directory entry is stored here, and it's marked as another unsigned integer. Lots of "10U 0" definitions for our structure, eh?
(5)
This field is marked as "reserved" and is an integer, which we know is defined as "10I 0" in RPG.
(6)
Yet another "reserved" field. This one is an 8-byte character field.
(7)
The national language support information is stored here. This information allows us to determine what CCSID we should be using to display the filename, as well as what language it is in, and what country it is from.

If we hunt for "qlg_nls_t" in the C header members, we'll find it defined in QSYSINC/SYS,TYPES. It is defined to be a data structure, containing four more subfields, an integer containing the CCSID, a 2-byte field containing the country-id, a 3-byte field containing the language ID, and a 3-byte reserved field.

(8)
This subfield contains the length of the filename that will be given in the next subfield. Since it is listed as an unsigned integer, we know that we need to make the RPG version use a "10U 0" variable.
(9)
Finally, what we've been waiting for! The name of the file that this directory entry refers to. The constant "_QP0L_DIR_NAME" defines the maximum length that the file name can be. If we hunt through the C header members, we will find that this constant is set to be the number 640.

So, here's our RPG version of the dirent structure. Note that we've based it on a pointer. This is important, since the readdir() API allocates the memory for this structure, consequently, we need to be able to point our structure at it's memory.

     D p_dirent        s               *                              
     D dirent          ds                  based(p_dirent)            
     D   d_reserved1                 16A                              
     D   d_fileno_gen_id...                                           
     D                               10U 0                            
     D   d_fileno                    10U 0                            
     D   d_reclen                    10U 0                            
     D   d_reserved3                 10I 0                            
     D   d_reserved4                  8A                              
     D   d_nlsinfo                   12A                              
     D     nls_ccsid                 10I 0 OVERLAY(d_nlsinfo:1)       
     D     nls_cntry                  2A   OVERLAY(d_nlsinfo:5)       
     D     nls_lang                   3A   OVERLAY(d_nlsinfo:7)       
     D     nls_reserv                 3A   OVERLAY(d_nlsinfo:10)      
     D   d_namelen                   10U 0                            
     D   d_name                     640A                              
   

Once we've added these to our IFSIO_H member, we'll be able to call the readdir() API like this:

     c                   eval      p_dirent = readdir(d)     
     c                   dow       p_dirent <> *NULL         
     C* ...do whatever we like with the contents             
     C*    of the dirent structure, here...                  
     c                   eval      p_dirent = readdir(d)     
     c                   enddo