我有一个驱动RPGLE程序的CMD命令对象。因为可以使用几个不同的参数调用命令,其中一些参数是互斥的,所以我使用RPGLE中的数据结构解析传递的参数,这样我就可以处理在不同位置传递参数的不同场景。
例如,CMD文件具有:
CMD PROMPT('Reprint Invoices and Credits')
PARM KWD(ORDERNUM) TYPE(ORDER) +
PROMPT('For order number:')
PARM KWD(INVDATE) TYPE(*DATE) PASSATR(*YES) +
PROMPT('For invoice date')
PARM KWD(DATERANGE) TYPE(DTRANGE) +
PROMPT('For date range:')
PARM KWD(TRANSTYPE) TYPE(*CHAR) LEN(9) RSTD(*YES) +
DFT(*BOTH) VALUES(*INVOICES *CREDITS *BOTH) +
PASSATR(*YES) PROMPT('Transactions to print')
DTRANGE: ELEM TYPE(*DATE) MIN(1) PASSATR(*YES) +
PROMPT('Beginning date')
ELEM TYPE(*DATE) MIN(1) PASSATR(*YES) +
PROMPT('Ending date')
ORDER: ELEM TYPE(*DEC) LEN(6) MIN(1) PASSATR(*YES) +
PROMPT('Order number')
ELEM TYPE(*DEC) LEN(2) MIN(0) PASSATR(*YES) +
PROMPT('Shipment number (optional)')
DEP CTL(*ALWAYS) PARM(ORDERNUM INVDATE DATERANGE) +
NBRTRUE(*EQ 1)
用户可以按各种标准打印:订单号,日期,日期范围。只能选择这三种方法中的一种。根据用户选择的内容,参数以不同方式传递给被调用的RPGLE程序。
********************************************************************
* Parameters from CMD object INV_REPRNT
D InputParms DS TEMPLATE QUALIFIED
D AllParms 143A
D ParmType 2 2A Can't find in manual
D 'Type' might be
D a misnomer
D
D OrdDteAttr 3 3A For attr's, see
D OrderNum 4 7P 0 SEU help for
D ShipAttr 8 8A CMD PASSATR
D Shipment 9 10P 0
D OrdInvCMAttr 21 21A
D OrdInvCM 22 30A char 9
D
D InvDate@ 4 10A
D DteInvCMAttr 13 13A
D DteInvCM 14 22A char 9
D
D BeginDateAttr 13 13A
D BeginDate@ 14 20A
D EndDateAttr 21 21A
D EndDate@ 22 28A
D RgeInvCMAttr 29 29A
D RgeInvCM 30 38A char 9
如您所见,后面的参数如TRANSTYPE
的位置根据选择的早期参数移位。 OrdInvCM
从22开始,DteInvCM
从14开始,RgeInvCM
从30开始。这不是问题,因为此数据结构和使用它的代码能够选择正确的位置根据我调用ParmType
的神秘小属性读取。据我所知,这个属性没有在互联网上的CL手册或SEU编辑器中包含的帮助中的任何地方记录(其中PASSATR
的信息不在在线手册中)。我已经将与ParmType
相关的一些PASSATR
行为拼凑起来,足以使用它,但还不足以完全理解它。
使解析 D Null C CONST(X'00')
D Parm2 C CONST(X'02')
D NumSpecd C CONST(X'A1') 1010 0001
D NumUnspecd C CONST(X'21') 0010 0001
D CharQSpecd C CONST(X'C5') 1100 0101 Quoted
D CharQUnspecd C CONST(X'45') 0100 0101 Quoted
D CharUQSpecd C CONST(X'85') 1000 0101 Unquoted
D CharUQUnspecd C CONST(X'05') 0000 0101 Unquoted
D
D IsSpecd C CONST(X'80') >= 1000 0000
更容易(不是每种可能性)的一些常量:
IF P.ParmType = Null;
IF P.OrdDteAttr >= IsSpecd;
// this is a single date
ELSE;
IF P.BeginDateAttr >= IsSpecd;
// this is a data range
ELSE;
// this is error condition I have not gotten yet
ENDIF;
ENDIF;
ELSE;
IF P.OrdDteAttr >= IsSpecd;
// this is an order number
ELSE;
// this is error condition I have not gotten yet
ENDIF;
ENDIF;
我发现:
ParmType
换句话说,ParmType
的十六进制值为' 00'当参数是日期或日期范围时。 ParmType
的十六进制值为' 02'当参数为'订单号'的打包* DEC(6P 0)时。
我想了解如何将[{"name":"Fressnapf","isChecked":true},{"name":"Whiskas","isChecked":true},{"name":"Purina","isChecked":true}]
值设置为给定数字,以便我可以强大地编写可以接受各种参数组合的程序。我也没有看到为什么数据范围字段从14开始而不是像单个日期那样在4开始的特定原因。我能够利用这个事实来做出必要的区分,但我不知道命令系统是否有意 ,因为它看到我有两种相同数据类型的可能性,或者这是只是一个幸运的休息,不能保证会发生。如果我想添加一个额外的打包参数作为选项,比如发票号,则会出现类似的问题。 ' PASSATR' ' A1'的十六进制值可以告诉你包装,但不是哪种类型(订单号或发票号)。可能是命令系统将位置移动到类似于日期范围的位置,但我没有运行该特定实验。
简而言之,是否有关于命令如何构建参数列表的文档或至少推导出的算法,以便人们可以预测这些字段将包含哪些内容以及它们将位于何处?
答案 0 :(得分:4)
无论是否输入值,都将传递所有参数,它们将按照命令中提供的顺序显示。
不应该需要 PASSATR
,请不要这样做。
CMD PROMPT('Reprint Invoices and Credits')
PARM KWD(ORDERNUM) TYPE(ORDER) +
PROMPT('For order number:')
PARM KWD(INVDATE) TYPE(*DATE) +
PROMPT('For invoice date')
PARM KWD(DATERANGE) TYPE(DTRANGE) +
PROMPT('For date range:')
PARM KWD(TRANSTYPE) TYPE(*CHAR) LEN(9) RSTD(*YES) +
DFT(*BOTH) VALUES(*INVOICES *CREDITS *BOTH) +
PROMPT('Transactions to print')
DTRANGE: ELEM TYPE(*DATE) MIN(1) +
PROMPT('Beginning date')
ELEM TYPE(*DATE) MIN(1) +
PROMPT('Ending date')
ORDER: ELEM TYPE(*DEC) LEN(6) MIN(1) +
PROMPT('Order number')
ELEM TYPE(*DEC) LEN(2) MIN(0) +
PROMPT('Shipment number (optional)')
DEP CTL(*ALWAYS) PARM(ORDERNUM INVDATE DATERANGE) +
NBRTRUE(*EQ 1)
混合列表ORDERNUM
和DATERANGE
将以整数个元素作为前两个字节出现。如果混合列表参数为空或未传递,则此整数将包含0。
以下是如何在CL
中编写命令处理程序的代码PGM PARM(&ORDERNUM &INVDATE &DATERANGE &TRANSTYPE)
DCL VAR(&ORDERNUM) TYPE(*CHAR)
DCL VAR(&ONELMCNT) TYPE(*INT) STG(*DEFINED) +
LEN(2) DEFVAR(&ORDERNUM 1)
DCL VAR(&ONORDER) TYPE(*DEC) STG(*DEFINED) LEN(6 +
0) DEFVAR(&ORDERNUM 3)
DCL VAR(&ONSHIPNO) TYPE(*DEC) STG(*DEFINED) +
LEN(2 0) DEFVAR(&ORDERNUM 7)
DCL VAR(&INVDATE) TYPE(*CHAR) LEN(7)
DCL VAR(&DATERANGE) TYPE(*CHAR)
DCL VAR(&DRELMCNT) TYPE(*INT) STG(*DEFINED) +
LEN(2) DEFVAR(&DATERANGE 1)
DCL VAR(&DRBDATE) TYPE(*CHAR) STG(*DEFINED) +
LEN(7) DEFVAR(&DATERANGE 3)
DCL VAR(&DREDATE) TYPE(*CHAR) STG(*DEFINED) +
LEN(7) DEFVAR(&DATERANGE 10)
DCL VAR(&TRANSTYPE) TYPE(*CHAR) LEN(9)
if (&onelmcnt *ne 0) do
/* ORDERNUM parameter has been entered */
enddo
if (&invdate *ne '0000000') do
/* INVDATE parameter has been entered */
enddo
if (&drelmcnt *ne 0) do
/* DATERANGE parameter has been entered */
enddo
if (&transtype *ne ' ') do
enddo
done: endpgm
请注意混合列表(ELEM
)参数的结构。如果列表中的元素数为0,则这些结构中只有元素计数&xxelmcnt
字段有效。另请注意,这些字段将始终包含0或2(每个列表中已定义元素的数量)。如果提供了ORDERNUM
参数,即使托运人编号留空,也会包含2。在这种情况下,为托运人编号传递的值将为0.
您可以在RPG程序中以类似的方式处理:
ctl-opt Main(testcmd);
dcl-ds ordernum_t qualified template;
elements Int(5);
order Packed(6:0);
shipper Packed(2:0);
end-ds;
dcl-ds daterange_t qualified template;
elements Int(5);
begindt Char(7);
enddt Char(7);
end-ds;
dcl-proc testcmd;
dcl-pi *n ExtPgm('TESTCMD');
ordernum LikeDs(ordernum_t) const;
invdate Char(7) const;
daterange LikeDs(daterange_t) const;
transtype Char(9) const;
end-pi;
if ordernum.elements <> 0;
// parameter has been entered
endif;
if invdate <> '0000000';
// parameter has been entered
endif;
if daterange.elements <> 0;
// parameter has been entered
endif;
if transtype <> '';
// parameter has been entered
endif;
return;
end-proc;
Here是关于如何处理混合列表参数的一些文档。在手册中包含它是简单列表的描述,以及列表中的列表(非常复杂)。
正如Charles所指出的那样,编辑,您试图在示例中将参数值作为单个块进行访问。这几乎可以保证引起混淆,因为除了程序中定义的参数引用之外,没有关于如何将参数加载到内存中的(公共)定义。参数通过引用传递,调用程序确定它们在内存中的位置。假设每个参数在物理上与前一个参数相邻可能是一个危险的假设。访问给定参数的唯一安全方法是使用其单独的参数引用。尝试从参数1的参考中访问参数2是一个坏主意。即使工作一次,也不一定总能奏效。如您所见,命令对象根据用户键在内存中移动内容。
由于我们知道上面的命令定义了4个参数,即4 PARM
个元素,我们可以确信4个参数中的每个参数都将完全按照命令中的定义传递给命令处理程序。 。但是,我们无法对内存中任何参数之后的内容充满信心。
答案 1 :(得分:2)
此处记录了PASSATR Pass attribute byte (PASSATR)
<强> *是
使用参数传递属性字节。
属性字节有两个字段:
Attribute Description
---------- --------------------------------------
'0000010'B Meets *NAME rules, like A_B
'0000100'B Meets GENERIC rules, like AB
'1000101'B Quoted character string, like 'A B'
'0000101'B Unquoted character string, like 5A
'1001000'B Logical constant, '0' or '1'
'0001100'B Hexadecimal value, like X'C1C2'
'0100001'B Unsigned numeric value, like 5
'0101001'B Unsigned numeric with decimal point,
like 5.2
'0110001'B Signed numeric value, like -5
'0111001'B Signed numeric with decimal point,
like -5.2
如果未指定(PASSVAL),请查看要传递的值,该文档位于PASSATR下方。
未指定时传递的值(PASSVAL)
指定值是否为 传递给该参数的命令处理程序。 * NULL是 如果参数是常量参数(参数中的参数),则无效 已为Constant值指定了一个值(CONSTANT) 参数,或* ZEROELEM或* NULL的参数 为值类型(TYPE)参数或列表/限定条件指定 由所有常量ELEM或QUAL语句定义的名称)。 *也是NULL 如果在返回值(RTNVAL)上指定了* YES,则无效 参数,或者为所需的最小值指定的值 (MIN)参数大于零。 DEP声明或REL和 其他PARM语句的RANGE关键字可能不指代的值 用* NULL定义的参数。
如果PASSVAL
未指定参数为* NULL,您应该能够在RPGLE中将其定义为OPTION(*OMIT)
,然后检查if %addr(myOptParm) <> 0;
修改强>
您尝试做的事情,将所有参数作为一个块传递是一个坏主意。您可能今天可以使用它,但它可能会因PTF的应用程序或操作系统升级而中断。该系统旨在传递单个参数。
将它们全部传递给您的RPG程序并检查实际使用的内容。
答案 2 :(得分:0)
我模糊地回忆起Bob Cozzi的一篇文章,其中谈到了PASSATR属性。也许它会有所帮助... https://www.mcpressonline.com/programming/rpg/retrieving-user-space-data