I'm trying to write a program in Control Language which creates and populates a configuration file in the IFS prior to calling a Java utility which uses it.
I've succeeded in calling the open() and close() APIs to (re)create the file but for the life of me I cannot get a write() to put something in the file. It has all been a learning experience so far, but with no error message on the write() call I'm having trouble seeing where my problem lies.
It's almost certainly the way I'm handling the variables, but a debug session suggests they are what they should be.
/* ========================================================================= */
/* Processing for the PRCMQMSG command */
/* ========================================================================= */
PGM PARM(&ACTION &SRCMQ &TGTMQ)
/* Input parameters */
DCL VAR(&ACTION) TYPE(*CHAR) LEN(5)
DCL VAR(&SRCMQ) TYPE(*CHAR) LEN(125)
DCL VAR(&TGTMQ) TYPE(*CHAR) LEN(125)
/* Parameter elements */
DCL VAR(&SRCHOST) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&SRCMQ 3)
DCL VAR(&SRCPORT) TYPE(*DEC) STG(*DEFINED) +
LEN(5) DEFVAR(&SRCMQ 33)
DCL VAR(&SRCQMGR) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&SRCMQ 36)
DCL VAR(&SRCCHNL) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&SRCMQ 66)
DCL VAR(&SRCQUE) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&SRCMQ 96)
DCL VAR(&TGTHOST) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&TGTMQ 3)
DCL VAR(&TGTPORT) TYPE(*DEC) STG(*DEFINED) +
LEN(5) DEFVAR(&TGTMQ 33)
DCL VAR(&TGTQMGR) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&TGTMQ 36)
DCL VAR(&TGTCHNL) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&TGTMQ 66)
DCL VAR(&TGTQUE) TYPE(*CHAR) STG(*DEFINED) +
LEN(30) DEFVAR(&TGTMQ 96)
/* IFS details */
DCL VAR(&PATH) TYPE(*CHAR) LEN(128) +
VALUE('/mqutil')
DCL VAR(&CFGFILE) TYPE(*CHAR) LEN(20)
DCL VAR(&JOB) TYPE(*CHAR) LEN(6)
/* IFS API flags */
DCL VAR(&O_RDONLY) TYPE(*INT) VALUE(1)
DCL VAR(&O_WRONLY) TYPE(*INT) VALUE(2)
DCL VAR(&O_RDWR) TYPE(*INT) VALUE(4)
DCL VAR(&O_CREAT) TYPE(*INT) VALUE(8)
DCL VAR(&O_EXCL) TYPE(*INT) VALUE(16)
DCL VAR(&O_TRUNC) TYPE(*INT) VALUE(64)
DCL VAR(&O_APPEND) TYPE(*INT) VALUE(256)
DCL VAR(&O_CODEPAGE) TYPE(*INT) VALUE(8388608)
DCL VAR(&O_TEXTDATA) TYPE(*INT) VALUE(16777216)
DCL VAR(&S_IRUSR) TYPE(*INT) VALUE(256)
DCL VAR(&S_IWUSR) TYPE(*INT) VALUE(128)
DCL VAR(&S_IXUSR) TYPE(*INT) VALUE(64)
DCL VAR(&S_IRWXU) TYPE(*INT) VALUE(448)
DCL VAR(&S_IRGRP) TYPE(*INT) VALUE(32)
DCL VAR(&S_IWGRP) TYPE(*INT) VALUE(16)
DCL VAR(&S_IXGRP) TYPE(*INT) VALUE(8)
DCL VAR(&S_IRWXG) TYPE(*INT) VALUE(56)
DCL VAR(&S_IROTH) TYPE(*INT) VALUE(4)
DCL VAR(&S_IWOTH) TYPE(*INT) VALUE(2)
DCL VAR(&S_IXOTH) TYPE(*INT) VALUE(1)
DCL VAR(&S_IRWXO) TYPE(*INT) VALUE(7)
/* IFS API parameters */
DCL VAR(&STROPN) TYPE(*INT) /* Open flags */
DCL VAR(&STRMODE) TYPE(*INT) /* Mode flags */
DCL VAR(&STRPATH) TYPE(*CHAR) LEN(149)
DCL VAR(&STRCODEP) TYPE(*INT) VALUE(819)
DCL VAR(&STRHAND) TYPE(*INT)
DCL VAR(&NULL) TYPE(*CHAR) LEN(1) VALUE(X'00')
DCL VAR(&CRLF) TYPE(*CHAR) LEN(2) VALUE(X'0D25')
DCL VAR(&ERRNO_PTR) TYPE(*PTR)
DCL VAR(&ERRNO) TYPE(*INT) STG(*BASED) +
BASPTR(&ERRNO_PTR)
DCL VAR(&ERRNO_CHR) TYPE(*CHAR) LEN(4)
DCL VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL VAR(&LINE) TYPE(*CHAR) LEN(250)
DCL VAR(&LINE_PTR) TYPE(*PTR) ADDRESS(&LINE)
DCL VAR(&LINELEN) TYPE(*UINT)
DCL VAR(&LINELEN_D) TYPE(*DEC) LEN(5 0)
/* Create and open a configuration file in the IFS */
RTVJOBA NBR(&JOB)
CHGVAR VAR(&CFGFILE) VALUE('mqconf_' |< &JOB)
CHGVAR VAR(&STRPATH) VALUE(&PATH |< '/' |< &CFGFILE +
|< '.connection' |< &NULL)
CHGVAR VAR(&STROPN) VALUE(&O_WRONLY + &O_CREAT + +
&O_TRUNC + &O_CODEPAGE + &O_TEXTDATA)
CHGVAR VAR(&STRMODE) VALUE(&S_IRWXU + &S_IRWXG + +
&S_IROTH)
CALLPRC PRC('open') PARM((&STRPATH) (&STROPN *BYVAL) +
(&STRMODE *BYVAL) (&STRCODEP *BYVAL)) +
RTNVAL(&STRHAND)
IF COND(&STRHAND = -1) THEN(DO)
CALLPRC PRC('__errno') RTNVAL(&ERRNO_PTR)
CHGVAR VAR(&ERRNO_CHR) VALUE(&ERRNO)
CHGVAR VAR(&MSGID) VALUE('CPE' || &ERRNO_CHR)
SNDPGMMSG MSGID(&MSGID) MSGF(QCPFMSG) MSGTYPE(*ESCAPE)
ENDDO
/* Write a line to the file */
CHGVAR VAR(&LINE) VALUE('This is a line of text in +
a file.' |< &CRLF)
RTVMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&LINE) +
MSGLEN(&LINELEN_D)
CHGVAR VAR(&LINELEN) VALUE(&LINELEN_D)
CALLPRC PRC('write') PARM((&STRHAND *BYREF) +
(&LINE_PTR *BYREF) (&LINELEN *BYVAL))
/* Close the configuration file */
CALLPRC PRC('close') PARM((&STRHAND *BYVAL))
ENDPGM
I had tried declaring the &LINE and &LINE_PTR variables in the same way as &ERRNO and &ERRNO_PTR but that gave me a Pointer not set error when I tried to assign the value to &LINE. I think that's because the &ERRNO_PTR is accessed first, whereas this was not the case for &LINE_PTR. Anyway, that may be a red herring.
The RTVMSG command is a trick to find the length of the string excluding trailing blanks.
I've run the code in debug and prior to the call to write() &LINE contains exactly what I expect, as does &LINELEN which is 35. Then the write() is called and causes no errors but neither is the line present in the file. The file remains empty.
A final note. All the parameters to the program are currently unused, but I have left in for completeness in case I've done something dumb with them. So essentially, the first two blocks of declarations can be ignored.
Any help appreciated.
You can use QSH and redirection to write to the IFS a lot easier than trying to use the C API.
/* DISABLE STDOUT */
ADDENVVAR ENVVAR(QIBM_QSH_CMD_OUTPUT) VALUE('NONE') REPLACE(*YES)
/* CREATE THE FILE WITH CCSID 819 */
ADDENVVAR ENVVAR(STRPATH) VALUE(&STRPATH) REPLACE(*YES)
QSH CMD('rm $STRPATH; touch -C 819 $STRPATH')
/* APPEND A LINE TO THE FILE */
ADDENVVAR ENVVAR(LINE) VALUE(&LINE) REPLACE(*YES)
QSH CMD('echo "$LINE">>$STRPATH')
For more information:
If you need higher performance you can use a more flexible HLL to access the API. Scott Klement has a great ebook titled Working with the IFS in RPG IV.