Sometimes its useful to be able to look up information about a stream file. Information such as the file's size, access permissions, and the time it was last modified are all available using the stat() API.
Here is the C-language prototype for the stat() API:
intstat(const char *path
, struct stat *buf
)
Here is the corresponding RPG prototype:
D stat PR 10I 0 ExtProc('stat') D path * value options(*string) D buf * value
In C, when you define a data structure, you first define the layout of the data structure. In this layout you list the subfields and their data types. Then, you declare variables that use this layout.
So, in that C-language prototype above, it tells us that buf is a pointer to any variable which uses the "stat layout".
Here is the definition for "struct stat" (the "stat layout") from the C language header member:
struct stat { mode_t st_mode; /* File mode */ ino_t st_ino; /* File serial number */ nlink_t st_nlink; /* Number of links */ uid_t st_uid; /* User ID of the owner of file */ gid_t st_gid; /* Group ID of the group of file */ off_t st_size; /* For regular files, the file * size in bytes */ time_t st_atime; /* Time of last access */ time_t st_mtime; /* Time of last data modification */ time_t st_ctime; /* Time of last file status change */ dev_t st_dev; /* ID of device containing file */ size_t st_blksize; /* Size of a block of the file */ unsigned long st_allocsize; /* Allocation size of the file */ qp0l_objtype_t st_objtype; /* AS/400 object type */ unsigned short st_codepage; /* Object data codepage */ char st_reserved1[62]; /* Reserved */ unsigned int st_ino_gen_id /* file serial number generation id */ };
The first line simply tells us that this is a structure definition called "stat".
The remaining lines, except for the last one, are a simple list of subfields, and their data types. For example, the last subfield in this data structure is called "st_ino_gen_id" and it is an unsigned integer.
To duplicate this in RPG, what we'll do is create a normal RPG data structure. But then, we'll base that structure on a pointer. Then, when we want to use the structure in our programs, we'll simply use the LIKE() keyword to declare character strings of the same size, and move the pointer so that we can reference the subfields. (Don't worry, if that's not clear to you, yet. I'll give you an example shortly that will help you understand.)
Also, you may have noticed that both the structure definition and the API are called "stat". That's not a problem in C since structure definitions use a separate name space from procedure calls. However, it is a problem in RPG. So, we'll call our data structure "statds" instead of "stat". That way, the name won't conflict with the name of the API.
Here is the RPG definition of the stat data structure:
D p_statds S * D statds DS BASED(p_statds) D st_mode 10U 0 D st_ino 10U 0 D st_nlink 5U 0 D st_pad 2A D st_uid 10U 0 D st_gid 10U 0 D st_size 10I 0 D st_atime 10I 0 D st_mtime 10I 0 D st_ctime 10I 0 D st_dev 10U 0 D st_blksize 10U 0 D st_allocsize 10U 0 D st_objtype 12A D st_codepage 5U 0 D st_reserved1 62A D st_ino_gen_id 10U 0
Now, when we call stat() in RPG, we'll do something like this:
D MyStat S like(statds) D MySize S 10I 0 * get stat info into "MyStat": c if stat('/path/to/file.txt': c %addr(mystat)) < 0 c callp EscErrno(errno) c endif * move structure to overlay the "mystat" info: c eval p_statds = %addr(mystat) * read the file's size into MySize: c eval MySize = st_size