5 CL、CMD其实有关这一章,以及屏幕文件的,在网上已经有很多人写过了,想了想,还是说一下吧。
5.1 CL 程序5.1.1 基本认识简单的理解,CL 程序就是和RPG 相对应的,是控制语言(Control Language)。
类型为CLP、CLLE 的源代码编译出来的程序,都属于CL 程序。
可能还是不够直观,这么说吧,我们在交互式命令行上输入的命令,用程序的方式来执行,这个执行的程序,就是CL 程序。
学过UNIX 的会比较好懂,CL 程序有点类似于SHELL,不过SHELL 是可以直接执行的,而且不用编译;CL 程序需要编译,而且要用CALL 的方式来执行。
不过原理是接近的,都是在程序中直接调用命令行的语句。
所以说,CL 程序其实很好写,只要会输入命令,就可以写CL 程序了。
在编辑CL 程序时,也可以用“命令+ F4”的方式来写,不需要老老实实的整行输入。
CL 程序不像RPGLE 程序,在编写时,可以使用自由格式书写;一行的内容如果太长要,在最末尾处用“+”表示换行举个最简单的例子,比如说新建个名为FHS01CL 的CLP 源程序,代码如下:PGMWRKACTJOBENDPGM编译此程序,然后CALL 之,系统就会执行命令WRKACTJOB,查看当前的活动作业,效果与在交互式命令行下输入WRKACTJOB 是一样的。
当我们输入F12,退出WRKACTJOB 时,系统就会继续向下执行,发现是ENDPGM,表示程序结束了,于是判定执行完毕,退出至交互式画面。
5.1.2 CL 程序的常用语法及命令:一、程序的开始与结束:PGM PARM(&A &B) /* 开始CL 程序*/ENDPGM /* 结束CL 程序*/CL 程序,和RPGLE 程序一样,也可以有程序的入口参数,而且程序的入口参数都是可传递的(也就是输入的参数如果在程序中被修改过,那么原调用的程序中的相应参数也会进行变化。
不过CL 的入口参数只能为字符型,或数字型的单个字段,不能象RPGLE 程序中那么多样化(字段、结构、数组、指针)。
如果CL 程序没有入口参数时,那么就可以不需要后面的PARM 语句,直接写成PGM即可。
写CL 程序时,不妨多使用F4,看看系统的帮助,这样就不用记那么多命令的参数名。
二、变量及其定义CL程序中的所有变量,都使用&做为前缀,这一点与RPGLE 程序不同。
比如说PGM PARM(&A &B)就表示入口参数为A、B 这两个变量在CL 程序中使用到的变量,都必须使用DCL 语句来定义:DCL VAR(&FLD01) TYPE(*CHAR) LEN(10)DCL VAR(&FLD02) TYPE(*DEC) LEN(10 2)上述语句表示:定义变量FLD01,10 位长的字符型变量定义变量FLD02,10 长,其中2 位小数的数字型变量除了字符、数字之外,CL 程序还可以定义逻辑变量(*LGL),逻辑变量允许的值只能为’1’或’0’。
不过通常有字符与数字也就够了。
CL 程序的主要功能在于进行命令处理,而不是处理字符串以及数据库三、CL 常用命令:CHGVAR -- 变量赋值CHGVAR VAR(&FLD01) VALUE(‘ABCD’)即是将变量FLD01 赋值成为’ABCD’(左对齐),同理,VALUE 的括号中也可以填写一个变量,即表示将此变量的值赋值到变量FLD01 中。
数字型变量的赋值同样也是使用CHGVAR 语句。
当变量中只包含数字时(0—9),数字型变量与字符型变量可以使用CHGVAR 语句进行转换,这一点与RPGLE 中的MOVE 语句比较类似。
IF -- 条件判断语句IF COND(&FLD01 *EQ '1') THEN(CHGVAR VAR(&FLD02) +VALUE('0'))当变量FLD01 等于’1’时,将变量FLD02 中的值更改为’0’THEN 后面,即是当符合条件时,要执行的命令。
写起来其实没有看上去那么复杂,多用F4 就会发现CL 程序写简单。
就比如上例,先写IF,然后按F4,在Condition 处填写条件语句,然后在Command 处填上CHGVAR,再按F4,再去填相应的处理语句,这样写,就比直接把整句抄下来就简单多了。
上面这种写法,只能在符合条件时,执行一条CL 语句;如果要执行多条,就必须写做:IF COND(&FLD01 *EQ '1') THEN(DO)CHGVAR VAR(&FLD02) VALUE(‘0’)其它执行语句ENDDO也就是THEN 后面,用DO,表示接下来的语句都是在这个IF 条件成立时才执行(DO)的。
然后结束处用ENDDO,必须要有。
ENDDO 在这里和循环没有任何关系,表示的是ENDIF 的意思,但是CL 语句里没有ENDIF,只有ENDDO。
IF 语句中,表示判断的关键字与RPGLE 中的Ifxx 操作码类似,有*EQ *GT *LT *GE *LE *NE用来表示逻辑关系的关键字有*AND, *OR, *NOTGOTO -- 跳转语句GOTO 语句与RPGLE 中的GOTO 是一样的,都是跳转的意思。
FHSTAG:GOTO CMDLBL(FHSTAG)注意,这里定义标签是用“:” 冒号MONMSG -- 监控错误信息我们使用CL 语句时,执行的命令可能会报出一些异常错误,从而导致整个程序中断,需要手工干预。
MONMSG 命令可以监控我们预定的错误信息,使CL 程序正常的向下运行。
举例而言,如果CL 程序中有如下语句:CALL PGM(FHS01R)MONMSG MSGID(CPF4131)则表示当系统调用程序FHS01R 时,如果发现有CPF4131(声明的文件重新编译过,但程序未重新编译)的错,那么CL 程序将不会异常中断,仅仅只是不运行程序FHS01R,然后继续向下执行CL 程序MONMSG 还可以用于在监控到错误信息之后,进行处理,如下:CALL PGM(FHS01R)MONMSG MSGID(CPF4131) EXEC(CHGVAR VAR(&FLD01) +VALUE('0'))这句话就表示当发现有CPF4131 的错误之时,将变量FLD01 赋值成为’0’如果要执行多句的话,和IF 语句的方法类似,也是使用DO 与ENDDO MONMSG MSGID(CPF4131) EXEC(DO)CHGVAR VAR(&FLD01) VALUE(‘0’)其它处理语句ENDDO5.1.3 不常用的语法%SST -- 取字符串CHGVAR VAR(&FLD01) VALUE(%SST(&FLD02 3 1))表示将字符变量FLD02,从第3 位开始,取1 位,左对齐赋值到变量FLD01 中。
%SST 的括号的参数中,第一个参数必须为字符型变量,第二个参数表示起始位,第三个参数表示要截取的长度。
*CAT -- 拼字符串DCL VAR(&FLD01) TYPE(*CHAR) LEN(10)CHGVAR VAR(&FLD01) VALUE('A' *CAT 'B')即表示将10 位长的字符型变量赋值成为’AB ‘‘A’,‘B’,也可以使用变量,如CHGVAR VAR(&FLD01) VALUE(&FLD02 *CAT &FLD03)要注意,*CAT 不能去掉字符串末尾的空,从效果上来看,有点类似于RPGLE 中的EVAL 操作码,而不是CAT 操作码+、-、*、/ -- 数学运算数字型变量,可以进行数学运算CHGVAR VAR(&FLD01) VALUE(&FLD01 + &FLD02)即等同于RPGLE 程序中的EVAL FLD01 = FLD01 + FLD02同理,-、*、/ 分别对应减、乘、除不过数学运行常用于RPGLE 程序中,较少用在CL 控制里面,这里只是介绍一下。
读取文件:(From Cuer:P1421)DCL VAR(&FLD01) TYPE(*CHAR) LEN(2)DCLF FILE(FHSLIB/PFFHS)RCVFCHGVAR VAR(&FLD01) VALUE(&FHS01)以上这段CL 的意思,就是在CL 程序中读取PFFHS 文件,然后将读到的第一条记录赋值到CL 的临时变量FLD01 中。
如果要将一个文件从头读到尾,则可以用如下语句来实现:DCLF FILE(FHSLIB/PFFHS)LOOP:RCVFMONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EXIT))读取到每条记录后的处理语句GOTO CMDLBL(LOOP)EXIT:也就是说,信息CPF0864,即表示未读取到记录。
在CL 程序中声明文件使用DCLF 语句,一个CL 文件中只能声明一个文件,声明语句必须在CL 控制语句之前。
使用声明的文件中的字段,同样需要在字段名前加上“&” ;CL 程序中,无法控制游标,无法对记录进行定位操作。
所以CL 程序对文件的操作是比较弱的,通常我最多只用来读取某些只含少量记录的参数文件。
5.2 CMDCMD 是用来生成命令的,执行后可以像其它系统命令一样,直接输入命令,或是F4,不需要像CLP 一样,要CALL 一下。
其实CMD 本质上也是执行CLP 或RPGLE(在编译时指定),用起来,无非就是好看点,直接一些,除此之外的意义,似乎也就没什么了。
举个例子,比如我们查看一个文件中的内容时,可以使用SQL 来查看,也可以使用命令RUNQRY 命令来实现(RUNQRY QRYFILE(文件名))。
但在我们要频繁查看文件时,这两种方式似乎都不是很爽,也就是说要输入的内容都不是最少的,那我们可以设计一个CMD,譬如说叫SEE,希望实现的最终效果,是在命令行输入“SEE 文件名”,就可以查看PF 文件中的记录。
那么,我们按如下步骤来实现:1. 建立一个CLP 程序,比如叫SEECLP,代码如下PGM PARM(&FILENAME)RUNQRY QRYFILE(&FILENAME)ENDPGM2. 编译此程序3. 建立一个CMD 程序(即源代码的属性为CMD),代码如下:CMD PROMPT(' 显示文件记录')PARM KWD(NAME) TYPE(*CHAR) LEN(10) MIN(1) +CHOICE(' 显示文件记录内容') +PROMPT('Display file record')4. 编译此CMD,用F4,可见如下画面:Create Command (CRTCMD)Type choices, press Enter.Command . . . . . . . . . . . . > SEE NameLibrary . . . . . . . . . . . > FHSLIB Name, *CURLIBProgram to process command . . . > SEE Name, *REXXLibrary . . . . . . . . . . . > *LIBL Name, *LIBL, *CURLIBSource file . . . . . . . . . . > FHSFILE NameLibrary . . . . . . . . . . . > FHSLIB Name, *LIBL, *CURLIBSource member . . . . . . . . . > SEE Name, *CMDThreadsafe . . . . . . . . . . . *NO *YES, *NO, *COND其中,蓝色字体显示的,就是我们需要输入这个CMD 要调用的程序名(默认值与CMD同名),这里我们将此项内容填为SEECLP,表示SEE 这个CMD,调用的是SEECLP 这个程序5. 编译成功之后,我们在命令行执行“SEE 文件名” ,就可以看到指定文件的记录。