Вызов API C API write() из CL в iSeries

Я пытаюсь написать программу на языке управления, которая создает и заполняет файл конфигурации в IFS перед вызовом утилиты Java, которая его использует.

Мне удалось вызвать API-интерфейсы open() и close() для (повторного) создания файла, но я не могу заставить запись() поместить что-то в файл. До сих пор все это было учебным опытом, но без сообщения об ошибке при вызове write() у меня возникли проблемы с пониманием того, в чем заключается моя проблема.

Почти наверняка именно так я обрабатываю переменные, но сеанс отладки предполагает, что они такие, какими должны быть.

/* ========================================================================= */
/* 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                                            

Я пытался объявить переменные &LINE и &LINE_PTR так же, как &ERRNO и &ERRNO_PTR, но это дало мне ошибку Pointer not set, когда я попытался присвоить значение &LINE. Я думаю, это потому, что сначала выполняется доступ к &ERRNO_PTR, тогда как для &LINE_PTR это не так. Во всяком случае, это может быть отвлекающим маневром.

Команда RTVMSG — это уловка, позволяющая найти длину строки, исключая конечные пробелы.

Я запустил код в режиме отладки, и перед вызовом write() &LINE содержит именно то, что я ожидал, как и &LINELEN, который равен 35. Затем вызывается write() и не вызывает ошибок, но при этом строка не присутствует в файл. Файл остается пустым.

Последнее замечание. Все параметры программы в настоящее время не используются, но я оставил их для полноты на случай, если я сделал с ними что-то глупое. Таким образом, первые два блока объявлений можно игнорировать.

Любая помощь приветствуется.


person zkarj    schedule 28.06.2012    source источник
comment
Вы заслуживаете плюса только за то количество времени, которое вам потребовалось, чтобы зайти так далеко.   -  person James Allman    schedule 28.06.2012
comment
JamesA дает хороший способ писать простые потоковые файлы IFS, используя только встроенные компоненты, но если вы хотите что-то установить (бесплатно и с открытым исходным кодом), iSeries Python — отличная альтернатива. Чем сложнее задача, тем лучше Python будет выглядеть рядом с CL.   -  person John Y    schedule 29.06.2012
comment
@JohnY Groovy отлично работает и на iSeries. Вся мощь Java с простотой и интерактивностью Python.   -  person James Allman    schedule 29.06.2012
comment
@JamesA: Groovy — отличный динамический язык шлюза для Java-программистов, но iSeries Python особенно хорошо подходит для IBM i, поскольку это родное приложение i (а не приложение JVM) и более жесткое интеграция с OS/400 (не помню, что такое текущий термин для операционной системы). iSeries Python — это больше, чем просто PASE-версия Python.   -  person John Y    schedule 29.06.2012
comment
Я всегда предпочитаю, чтобы мой код был как можно более «родным». Обычно я избегаю использования TAATOOL, несмотря на то, что у нас есть лицензия на него в течение многих лет, просто потому, что он может исчезнуть. Принимая во внимание, что использование нативных API гарантированно продолжит работу, и я могу портировать его куда угодно. У меня есть окончательный инструмент, работающий сейчас с использованием метода QSH. Теперь я могу вводить простую команду с подсказкой вместо того, чтобы каждый раз вручную редактировать файлы конфигурации. Я подожду немного и посмотрю, ответит ли кто-нибудь на вопрос write(), а если нет, то я отмечу QSH как ответ.   -  person zkarj    schedule 29.06.2012


Ответы (3)


Вы можете использовать QSH и перенаправление для записи в IFS намного проще, чем пытаться использовать 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')

Чтобы получить больше информации:


Если вам нужна более высокая производительность, вы можете использовать более гибкий HLL для доступа к API. У Скотта Клемента есть отличная электронная книга под названием Работа с IFS в RPG IV.

person James Allman    schedule 28.06.2012
comment
Спасибо, Джеймс, это действительно выглядит намного проще! Часть меня (часть хакера/программиста) все еще хочет знать, почему write() не работает, но, в конце концов, важно выполнить работу. - person zkarj; 29.06.2012
comment
О, небольшая поправка к вашему коду. Первым параметром ADDENVVAR является ENVVAR(), а не VAR(). Но для этого и нужен F4. :-) - person zkarj; 29.06.2012
comment
Аллилуйя! Это кажется немного медленным, но это не имеет значения в данном случае. И это работает! ` *************Начало данных*************** Это строка текста в файле. ************Конец данных******************** ` Теперь, чтобы сделать это полезным... :-) - person zkarj; 29.06.2012
comment
@zkarj Исправлено, спасибо. В исходном ответе использовалась конкатенация переменных, но я изменил его, чтобы использовать переменные среды для более чистого примера. - person James Allman; 29.06.2012
comment
Никогда не помешает указать кому-нибудь на материал Скотта Клемента, который неизменно превосходен. И по моему личному опыту, RPG IV — это лучшее место с точки зрения баланса между простотой программирования и скоростью исполнения. Но при работе как с файлами QSYS.LIB, так и с файлами потоков IFS, я не думаю, что что-либо сравнится с iSeries Python по простоте программирования (и его производительность часто лучше, чем у Java на i). - person John Y; 29.06.2012

Я искал, как использовать API-интерфейсы IFS от CL, и наткнулся на ваш код. Я думаю, что ваша проблема с записью заключается в том, что дескриптор файла (первый параметр) должен передаваться по значению. Кроме того, не указывайте O_CODEPAGE в переменной &STROPN, так как это конфликтует с параметром кодовой страницы. Я использую этот метод и могу получить хороший файл трассировки для служебной программы, над которой я работаю.

person Michael    schedule 20.08.2014

Это всего лишь небольшая ошибка в вызове функции записи, дескриптор должен передаваться по значению, а не по ссылке Найдите ниже исправленный вызов записи, я протестировал его и он работает

CALLPRC    PRC('write') PARM((&STRHAND *BYVAL) +    
         (&LINE_PTR *BYREF) (&LINELEN *BYVAL))  
person wikiwikiweb    schedule 08.09.2015
comment
Ой, извините, не увидела ответа от Майкла, извините за это - person wikiwikiweb; 08.09.2015