Opening and creating IFS files using C API open in RPGLE |
Open() API
The open() function opens a file and returns a number named as a file descriptor. Each file opened by an open() gets a new file descriptor.
Work with Objects Type options, press Enter. 2=Edit authority 3=Copy 4=Delete 5=Display authority 7=Rename 8=Display description 13=Change description Opt Object Type Library Attribute Text QP0LLIB1 *SRVPGM QSYS CPPLE
Display Service Program Information Display 5 of 10 Service program . . . . . . . . . . . . : QP0LLIB1 Library . . . . . . . . . . . . . . . : QSYS Owner . . . . . . . . . . . . . . . . . : QSYS Service program attribute . . . . . . . : CPPLE Detail . . . . . . . . . . . . . . . . . : *PROCEXP Procedure Exports: Procedure Name ARGOPT lseek *NO lstat *NO mkdir *NO open *NO opendir *NO pathconf *NO read *NO readdir *NO readlink *NO readv *NO More...
Prototype of Open() in C
A prototype tells the compiler how the parameters of a called program or procedure are defined.
int open(const char *path, int oflag, . . .)
- int: It tells what type of value this open() api returns. The int data type in C is equivalent to "10 I 0" in RPGLE.
- open: This is the name of the sub-procedure being called. Procedure names are case sensitive in C. However, In RPG procedure names are not case sensitive. Therefore, when we use C apis like open() we do use EXTPROC() keyword to refer to the open() as all lower case. The actual name we use for open() while defining in RPG will be converted to all upper case by the compiler before binding.
- const char *path: This is the ifs path where we want to create/open a stream file. The char means character and the * means pointer. Therefore, we need to pass a pointer that points to a character variable. In C, character strings are read by a starting point in memory and reading forward until a X'00' (NULL) is encountered. In RPG, we have OPTIONS(*STRING) and the %STR() built-in function available that can be used to convert the C string to and from RPG supported format.
- int oflag: This is Integer data type which defines the flags used by the open() api. The int data type in C is equivalent to "10 I 0" in RPGLE.
- . . .: The three periods tells us that any number of optional parameters may be defined. But in RPG we must know number of input parameters in advance. There are only two optional parameters that can be specified and both must be unsigned integers. One is for specifying the mode for providing authorities to the ifs stream file to be created and the other one is a code page which is used to provide the ccsid in which the stream file will be created and supports.
RPGLE prototype for open() API
Let's see how we will consume this C API in the RPGLE program. The prototype of open() is as follows.
D open PR 10I 0 extproc('open') D ifspath * value options(*string) D oflag 10I 0 value D mode 10U 0 value options(*nopass) D codepage 10U 0 value options(*nopass)
- The first thing is all the input parameters are defined as passed by value. That's because C api open() expects to receive a pointer, integer, optional unsigned integer and again optional unsigned integer. If we pass these parameters by reference, then open() api would receive 4 memory addresses instead of value.
- The second thing is the first parameter i.e. ifs path that expects pass by reference instead of pass by value. However, we are still passing that using pass by value just because you can notice i still defined ifspath as * pointer since the C allows the ifs path to be of any length. Therefore, passing a pointer by value is same as passing a variable by reference that passes the address in memory to the open() api. Since we used pointer by value and we also used options(*string) so that RPG compiler will automatically allow any length of string to be passed and convert it to C language format by adding the X'00' (NULL) terminating character at the end of the string.
- At last, we used options(*nopass) with mode and codepage parameters that tells the compiler that these are optional parameters to be passed during the open() api call.
Parameters of open() api
ifspath parameter
(Input) A pointer to the null-terminated path name of the file to be opened. This is the file name that we want to create/open using the open() api.
In IFS, this "/" character is used to separate the different directories and finally the file itself. The first "/" character specifies the root directory. After that, each name separated by the "/" chracter would be a directory name until we reach to the file name.
Let's see the below path name:
/home/easyclass/openfile1
Here, the first "/" means start at the root directory of the ifs. If we have not started the ifs path from the first "/" character then it would start and continue from the user current directory. Here the filename is "openfile1".
oflag parameter
(Input) It specifies the options to be used during ifs file creation/opening. We actually pass a string of 32 bits each which specifies a different options.
Let's discuss the bits passed for different options when accessing(create/open) the ifs file in form of flags since each bits serves a different purpose and also each flag sets only one bit to ON for supplying different opening/creation modes for the file.
- O_readonly
- O_writeonly
- O_readwrite
- O_createfileifnotexist
- O_exclusivecreate
- O_truncateto0bytes
- O_appendtofile
- O_converttextbycodepage
- O_openintextmode
Opening a file to read only. The rightmost bit specifies the "Read only". We would be defining the below constant named O_readonly in RPGLE program and with decimal value of 1. Therefore, for opening file in "Read only" mode we need set the first bit to ON.
D O_readonly C 1
Decimal | Binary |
---|---|
1 | 0000000000000001 |
You may convert decimal to the binary from Convert decimal to binary.
Opening a file to write only. Then moving one bit to the left from the rightmost bit specifies the "Write only". We would be defining the below constant named O_writeonly in RPGLE program and with decimal value of 2. Therefore, for opening file in "Write only" mode we need set the second bit to ON.
D O_writeonly C 2
Decimal | Binary |
---|---|
2 | 0000000000000010 |
You may convert decimal to the binary from Convert decimal to binary.
Open for both reading and writing. Then moving two bits to the left from the rightmost bit specifies the "Read and Write". We would be defining the below constant named O_readwrite in RPGLE program and with decimal value of 4. Therefore, for opening file in "Reading and Writing" mode we need set the third bit to ON.
D O_readwrite C 4
Decimal | Binary |
---|---|
4 | 0000000000000100 |
You may convert decimal to the binary from Convert decimal to binary.
To check whether a path exists or not. Then moving three bits to the left from the rightmost bit specifies the "Create file if not exists". We would be defining the below constant named O_createfileifnotexist in RPGLE program and with decimal value of 8. Therefore, for "Creating the file if not exists" we need set the fourth bit to ON.
D O_createfileifnotexist... D C 8
Decimal | Binary |
---|---|
8 | 0000000000001000 |
You may convert decimal to the binary from Convert decimal to binary.
open() fails if the file already exists. Then moving four bits to the left from the rightmost bit specifies the "Exclusively create the file". We would be defining the below constant named O_exclusivecreate in RPGLE program and with decimal value of 16. Therefore, for "Exclusively create the file" we need set the fifth bit to ON.
D O_exclusivecreate... D C 16
Decimal | Binary |
---|---|
16 | 0000000000010000 |
You may convert decimal to the binary from Convert decimal to binary.
Truncate the file to zero length. Then moving six bits to the left from the rightmost bit specifies the "Truncate file to 0 bytes". We would be defining the below constant named O_truncateto0bytes in RPGLE program and with decimal value of 64. Therefore, for "Truncate file to 0 bytes" we need set the seventh bit to ON.
D O_truncateto0bytes... D C 64
Decimal | Binary |
---|---|
64 | 0000000001000000 |
You may convert decimal to the binary from Convert decimal to binary.
Position the file offset at the end of the file before each write operation. Then moving eight bits to the left from the rightmost bit specifies the "Append to File". We would be defining the below constant named O_appendtofile in RPGLE program and with decimal value of 256. Therefore, for "Append to File" we need set the nineth bit to ON.
D O_appendtofile C 256
Decimal | Binary |
---|---|
256 | 0000000100000000 |
You may convert decimal to the binary from Convert decimal to binary.
The call to open has a fourth optional argument (conversion ID), which is to be interpreted as a code page. Then moving twenty three bits to the left from the rightmost bit specifies the "Convert text by codepage". We would be defining the below constant named O_converttextbycodepage in RPGLE program and with decimal value of 8388608. Therefore, for "Convert text by codepage" we need set the twenty fourth bit to ON.
D O_converttextbycodepage... D C 8388608
Decimal | Binary |
---|---|
8388608 | 00000000100000000000000000000000 |
You may convert decimal to the binary from Convert decimal to binary.
Open the file in Text mode. Then moving twenty four bits to the left from the rightmost bit specifies the "Open in Text mode". We would be defining the below constant named O_openintextmode in RPGLE program and with decimal value of 16777216. Therefore, for "Open in Text mode" we need set the twenty fifth bit to ON.
D O_openintextmode... D C 16777216
Decimal | Binary |
---|---|
16777216 | 00000001000000000000000000000000 |
You may convert decimal to the binary from Convert decimal to binary.
Suppose, we want to create a file and open that in read only mode then we need to set ON the 4th bit(decimal 8) and 1st bit (decimal 1) from the rightmost which means we need to pass the decimal value as 8+1 = 9 (binary 0000000000001001). Therefore, In this case in oflag parameter we pass oflag = vO_createfileifnotexist + O_readonly;
mode parameter
It specifies the file permission bits to be used when a file is created. Like the oflag parameter, this parameter too treated as series of bits to be passed. Here, we use the rightmost 9 bits for providing file authorities.
user: owner group other permission: R W X R W X R W X bit: 9 8 7 6 5 4 3 2 1
These 8 rightmost bits specifies the file permissions to 3 types of users.The first is the file's owner, the second is users with the same group profile as the file's owner, and the third is all other users.
- M_readowner
- M_writeowner
- M_executeowner
- M_readgroup
- M_writegroup
- M_executegroup
- M_readother
- M_writeother
- M_executeother
- First, we initialize the ifs path variable with the path name for the stream file to be created at IFS. Here, file named "openfile1" will be created in user, current home directory.
- Initialize the oflag parameter of the OPEN() api with flags O_createfileifnotexist and O_readwrite which means if file is not present at ifs path then create it first and then open it in read and write mode.
- Initialize the mode parameter of the OPEN() api with flag M_writeowner which means at the time of file creation provide only write authority to the owner and no authorities to the others/group users.
- Call the OPEN() api by passing ifspath variable, flag variable and optional mode variable(mode variable is only applicable at the time of file creation if not exist otherwise it is not required to pass. Once the OPEN() api got executed it will return the file descriptor in variable named "filedescriptor".
- Finally, check whether filedescriptor is less than zero then return from the program which means file was not opened by the OPEN() api and any error occurs during file open. This filedescriptor is associated with the file being opened and is unique for each file being opened by the OPEN() api. It is later used by other IFS C api to know which file has to be operated.
- Compile the above RPGLE program by either using command CRTSQLRPGI or option 14 on source member of type SQLRPGLE.
- Call the program using call command CALL <program Name> from the IBM i command line.
- For output- IFS file created. Type WRKLNK command on the IBM i command line and press Enter to work with IFS links.
Read only permission to the file owner. Then moving eigt bits to the left from the rightmost bit specifies the "Read only authority for file owner". We would be defining the below constant named M_readowner in RPGLE program and with decimal value of 256. Therefore, for providing "Read only authority for file owner" we need set the nineth bit to ON.
D M_readowner C 256
Decimal | Binary |
---|---|
256 | 0000000100000000 |
You may convert decimal to the binary from Convert decimal to binary.
Write only permission to the file owner. Then moving seven bits to the left from the rightmost bit specifies the "Write only authority for file owner". We would be defining the below constant named M_writeowner in RPGLE program and with decimal value of 128. Therefore, for providing "Write only authority for file owner" we need set the eighth bit to ON.
D M_writeowner C 128
Decimal | Binary |
---|---|
128 | 0000000010000000 |
You may convert decimal to the binary from Convert decimal to binary.
Read, write, and execute permission to the file owner. Then moving six bits to the left from the rightmost bit specifies the "Execute authority for file owner". We would be defining the below constant named M_executeowner in RPGLE program and with decimal value of 64. Therefore, for providing "Execute authority for file owner" we need set the seventh bit to ON.
D M_executeowner C 64
Decimal | Binary |
---|---|
64 | 0000000001000000 |
You may convert decimal to the binary from Convert decimal to binary.
Read only permission to the group users of the owner profile. Then moving five bits to the left from the rightmost bit specifies the "Read only authority for all the group users of owner's profile". We would be defining the below constant named M_readgroup in RPGLE program and with decimal value of 32. Therefore, for providing "Read only authority for all the group users of owner's profile" we need set the sixth bit to ON.
D M_readgroup C 32
Decimal | Binary |
---|---|
32 | 0000000000100000 |
You may convert decimal to the binary from Convert decimal to binary.
Write only permission to the group users of the owner profile. Then moving four bits to the left from the rightmost bit specifies the "Write only authority for all the group users of owner's profile". We would be defining the below constant named M_writegroup in RPGLE program and with decimal value of 16. Therefore, for providing "Write only authority for all the group users of owner's profile" we need set the fifth bit to ON.
D M_writegroup C 16
Decimal | Binary |
---|---|
16 | 0000000000010000 |
You may convert decimal to the binary from Convert decimal to binary.
Read, write, and execute permission to the group users of the owner profile. Then moving three bits to the left from the rightmost bit specifies the "Execute authority for all the group users of owner's profile". We would be defining the below constant named M_executegroup in RPGLE program and with decimal value of 8. Therefore, for providing "Execute authority for all the group users of owner's profile" we need set the fourth bit to ON.
D M_executegroup C 8
Decimal | Binary |
---|---|
8 | 0000000000001000 |
You may convert decimal to the binary from Convert decimal to binary.
Read only permission to other users. Then moving two bits to the left from the rightmost bit specifies the "Read only authority for all other users than owner and group users of owner's profile". We would be defining the below constant named M_readother in RPGLE program and with decimal value of 4. Therefore, for providing "Read only authority for all other users than owner and group users of owner's profile" we need set the third bit to ON.
D M_readother C 4
Decimal | Binary |
---|---|
4 | 0000000000000100 |
You may convert decimal to the binary from Convert decimal to binary.
Write only permission to other users. Then moving one bit to the left from the rightmost bit specifies the "Write only authority for all other users than owner and group users of owner's profile". We would be defining the below constant named M_writeother in RPGLE program and with decimal value of 2. Therefore, for providing "Write only authority for all other users than owner and group users of owner's profile" we need set the second bit to ON.
D M_writeother C 2
Decimal | Binary |
---|---|
2 | 0000000000000010 |
You may convert decimal to the binary from Convert decimal to binary.
Read, write, and execute permissions to other users. The rightmost bit specifies the "Execute authority for all other users than owner and group users of owner's profile". We would be defining the below constant named M_executeother in RPGLE program and with decimal value of 1. Therefore, for providing "Execute authority for all other users than owner and group users of owner's profile" we need set the first bit to ON.
D M_executeother C 1
Decimal | Binary |
---|---|
1 | 0000000000000001 |
You may convert decimal to the binary from Convert decimal to binary.
Suppose, we want to provide owner as read aithority on the file (set 9th bit to ON - decimal 256) and group user has only read authority (set 6th bit to ON - decimal 32) and no permission to other users. Then we can pass the above flags to mode parameter after summing them up. Therefore, we actually need to set 6th and 9th bit to ON whose decimal equivalent is 32 + 256 = 288 (binary 0000000100100000). Therefore we can pass like mode = M_readowner + M_readgroup;
codepage parameter
If we specify O_converttextbycodepage flag (binary = 00000000100000000000000000000000 and decimal =8388608) in the oflag paramter i.e. setting 24th bit to ON, Then we must pass the optional parameter codepage for specifying the ccsid to be associated with the file during file creation using open() api.
File descriptor: The return value of the open() API
The open() api returns file descriptor of type integer (10 I 0). This file descriptor is later passed to all other IFS C apis which we will discuss later in our next articles. This file descriptor tells other api about the file that is opened and referred to. In case file is not opened using open() api and some error occurs, then open() api will return the file descriptor as -1. So, whenever we call open() api we check for this file descriptor and if its -1 we consider this as an error.
RPGLE program using C API open() to create/open ifs stream file.
HDFTACTGRP(*NO) D open PR 10I 0 extproc('open') D ifspath * value options(*string) *ifs path D oflag 10I 0 value *string of 32 bits D mode 10U 0 value options(*nopass) * 9 bits D codepage 10U 0 value options(*nopass) * * -----oflag---- D O_readonly C 1 D O_writeonly C 2 D O_readwrite C 4 D O_createfileifnotexist... D C 8 D O_exclusivecreate... D C 16 D O_truncateto0bytes... D C 64 D O_appendtofile C 256 D O_converttextbycodepage... D C 8388608 D O_openintextmode... D C 16777216 * * -----mode---- * owner,group,other (RWX) * owner authority D M_readowner C 256 D M_writeowner C 128 D M_executeowner C 64 * group authority D M_readgroup C 32 D M_writegroup C 16 D M_executegroup C 8 * other people D M_readother C 4 D M_writeother C 2 D M_executeother C 1 * Difspath s 512a Doflag s 10I 0 Dmode s 10U 0 Dcodepage s 10U 0 Dfiledescriptor s 10i 0 C EVAL ifspath = '/home/easyclass/openfile1' C EVAL oflag = O_readwrite + C O_createfileifnotexist C EVAL mode = M_writeowner C EVAL filedescriptor = open(%trim(ifspath): C oflag: C mode) C IF filedescriptor < 0 C RETURN C ENDIF C EVAL *INLR = *ON C RETURN
HDFTACTGRP(*NO) D open PR 10I 0 extproc('open') D ifspath * value options(*string) *ifs path D oflag 10I 0 value *string of 32 bits D mode 10U 0 value options(*nopass) * 9 bits D codepage 10U 0 value options(*nopass) * * -----oflag---- D O_readonly C 1 D O_writeonly C 2 D O_readwrite C 4 D O_createfileifnotexist... D C 8 D O_exclusivecreate... D C 16 D O_truncateto0bytes... D C 64 D O_appendtofile C 256 D O_converttextbycodepage... D C 8388608 D O_openintextmode... D C 16777216 * * -----mode---- * owner,group,other (RWX) * owner authority D M_readowner C 256 D M_writeowner C 128 D M_executeowner C 64 * group authority D M_readgroup C 32 D M_writegroup C 16 D M_executegroup C 8 * other people D M_readother C 4 D M_writeother C 2 D M_executeother C 1 * Difspath s 512a Doflag s 10I 0 Dmode s 10U 0 Dcodepage s 10U 0 Dfiledescriptor s 10i 0 /free ifspath = '/home/easyclass/openfile1'; oflag = O_readwrite + O_createfileifnotexist; mode = M_writeowner ; filedescriptor = open(%trim(ifspath): oflag: mode); if filedescriptor < 0; return; endif; *inlr = *on; return; /end-free
**FREE CTL-OPT DFTACTGRP(*NO); DCL-PR open int(10) EXTPROC('open'); ifspath pointer VALUE options(*string); oflag int(10) VALUE; mode uns(10) VALUE options(*nopass); codepage uns(10) VALUE options(*nopass); END-PR; // * -----oflag---- DCL-C O_readonly 1; DCL-C O_writeonly 2; DCL-C O_readwrite 4; DCL-C O_createfileifnotexist 8; DCL-C O_exclusivecreate 16; DCL-C O_truncateto0bytes 64; DCL-C O_appendtofile 256; DCL-C O_converttextbycodepage 8388608; DCL-C O_openintextmode 16777216; // * -----mode---- // * owner,group,other (RWX) // * owner authority DCL-C M_readowner 256; DCL-C M_writeowner 128; DCL-C M_executeowner 64; // * group authority DCL-C M_readgroup 32; DCL-C M_writegroup 16; DCL-C M_executegroup 8; // * other people DCL-C M_readother 4; DCL-C M_writeother 2; DCL-C M_executeother 1; DCL-S ifspath CHAR(512); DCL-S oflag int(10); DCL-S mode uns(10); DCL-S codepage uns(10); DCL-S filedescriptor int(10); ifspath = '/home/easyclass/openfile1'; oflag = O_readwrite + O_createfileifnotexist; mode = M_writeowner ; filedescriptor = open(%trim(ifspath): oflag: mode); if filedescriptor < 0; return; endif; *inlr = *on; return;
Brief Explanation of the RPGLE code using OPEN() ifs C api
Compile-Run-Output of the above program
Work with Object Links Directory . . . . : /home/EASYCLASS Type options, press Enter. 2=Edit 3=Copy 4=Remove 5=Display 7=Rename 8=Display attributes 11=Change current directory ... Opt Object link Type Attribute Text . DIR .. DIR append STMF core STMF csv1.csv STMF employeeTable.html STMF helloworld STMF lseek STMF openfile1 STMF