如何於 RPG中 針對所定義的資料結構(DataStructure)排序?(C API QSORT)
於 RPG 中,若要針對矩陣排序相信大家都會使用 SORTA ,但 SORTA 並無法針對
D spec 資料結構的特定欄位排序,若要針對資料結構排序須使用 C API QSORT,V5R1 後,
ILE RPG 支援指定(Qualified)資料結構的欄位範例如下:
File : QRPGLESRC
Member: QSORTR
Type : RPGLE
Usage : CRTBNDRPG QSORTR
CALL QSORTR
OS Version: V5R1
H DFTACTGRP(*NO) BNDDIR('QC2LE')
D qsort PR ExtProc('qsort')
D base * value
D num 10U 0 value
D width 10U 0 value
D compare * procptr value
D SortByItem PR 10I 0
D parm1 likeds(Order)
D parm2 likeds(Order)
D SortByQty PR 10I 0
D parm1 likeds(Order)
D parm2 likeds(Order)
D Order DS based(prototype_only)
D Qualified
D DtlItem 12A
D DtlOrdQty 5S 0
D Order1 DS likeds(Order) dim(99)
D numitems s 10I 0
D idx s 10I 0
D tmpstr s 50
D tmpnbr s 10I 0
** Throw some sample data into array to test it.
c eval order1(1).DtlItem = 'ZZ123'
c eval order1(1).DtlOrdQty = 5
c eval order1(2).DtlItem = 'BB321'
c eval order1(2).DtlOrdQty = 17
c eval order1(3).DtlItem = 'RR826'
c eval order1(3).DtlOrdQty = 14
c eval order1(4).DtlItem = 'AA000'
c eval order1(4).DtlOrdQty = 3
c eval numitems = 4
** Sort the array by DtlItem
c callp qsort(%addr(Order1): numitems:
c %size(Order): %paddr('SORTBYITEM'))
c For idx= 1 to numitems
c eval tmpstr = order1(idx).DtlItem
c Dsply tmpstr
c Endfor
** Sort the array by DtlOrdQty
c callp qsort(%addr(Order1): numitems:
c %size(Order): %paddr('SORTBYQTY'))
c For idx= 1 to numitems
c eval tmpnbr = order1(idx).DtlOrdQty
c Dsply tmpnbr
c Endfor
c eval *inlr = *on
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P SortByItem B
D SortByItem PI 10I 0
D parm1 likeds(Order)
D parm2 likeds(Order)
c select
c when parm1.DtlItem < parm2.DtlItem
c return -1
c when parm1.DtlItem > parm2.DtlItem
c return 1
c other
c return 0
c endsl
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P SortByQty B
D SortByQty PI 10I 0
D parm1 likeds(Order)
D parm2 likeds(Order)
c select
c when parm1.DtlOrdQty < parm2.DtlOrdQty
c return -1
c when parm1.DtlOrdQty > parm2.DtlOrdQty
c return 1
c other
c return 0
c endsl
P E
A blog about IBM i (AS/400), MQ and other things developers or Admins need to know.
星期一, 11月 06, 2023
2003-12-09 如何於 RPG中 針對所定義的資料結構(DataStructure)排序?(C API QSORT)
2003-08-26 如何於 CLP 中列出 PF 的 Member ? (API QUSLMBR)
如何於 CLP 中列出 PF 的 Member ? (API QUSLMBR)
有二種方式:
1.
PGM
DCLF QAFDMBRL
DSPFD FILE(lib/file) TYPE(*MBRLIST) OUTPUT(*OUTFILE) OUTFILE(lib/MBRLIST)
OVRDBF FILE(QAFDMBRL) TOFILE(lib/MBRLIST)
LOOP:
RCVF
MONMSG CPF0864 EXEC(GOTO END)
SNDPGMMSG MSG(&MLNAME)
GOTO LOOP
END:
DLTOVR FILE(*ALL)
ENDPGM
2. API QUSLMBR
Usage: CRTCLPGM LSTMBRC
CALL LSTMBRC('lib' 'file')
/*-------------------------------------------------------------------*/
/* LSTMBRC - List processing for file members - Example Pgm */
/* */
/* This program was done as an example of working with APIs in */
/* a CL program. */
/* */
/*-------------------------------------------------------------------*/
/* Program Summary: */
/* */
/* Initialize binary values */
/* Create user space (API CALL) */
/* Load user space with member names (API CALL) */
/* Extract entries from user space (API CALL) */
/* Loop until all entries have been processed */
/* */
/*-------------------------------------------------------------------*/
/* API (application program interfaces) used: */
/* */
/* QUSCRTUS create user space */
/* QUSLMBR list file members */
/* QUSRTVUS retrieve user space */
/* See SYSTEM PROGRAMMER'S INTERFACE REFERENCE for API detail. */
/* */
/*-------------------------------------------------------------------*/
PGM (&LIB &FILE)
DCL &LIB *CHAR 10
DCL &FILE *CHAR 10
/*-------------------------------------------------------------------*/
/* $POSIT - binary fields to control calls to APIs. */
/* #START - get initial offset, # of elements, length of element. */
/*-------------------------------------------------------------------*/
DCL &STARTC *CHAR 4 /* $POSIT */
DCL &LENGTC *CHAR 4 /* $POSIT */
DCL &STARTN *CHAR 16
DCL &OFSET *DEC (7 0)
DCL &ELEMS *DEC (7 0)
DCL &LENGT *DEC (7 0)
/*-------------------------------------------------------------------*/
/* Error return code parameter for the APIs */
/*-------------------------------------------------------------------*/
DCL &DSERR *CHAR 256
DCL &BYTPV *CHAR 4
DCL &BYTAV *CHAR 4
DCL &MSGID *CHAR 7
DCL &RESVD *CHAR 1
DCL &EXDTA *CHAR 240
/*-------------------------------------------------------------------*/
/* Define the fields used by the create user space API. */
/*-------------------------------------------------------------------*/
DCL &SPACE *CHAR 20 ('LSTOBJR QTEMP ')
DCL &EXTEN *CHAR 10 ('TEST')
DCL &INIT *CHAR 1 (X'00')
DCL &AUTHT *CHAR 10 ('*ALL')
DCL &APITX *CHAR 50
DCL &REPLA *CHAR 10 ('*NO')
/*-------------------------------------------------------------------*/
/* various other fields */
/*-------------------------------------------------------------------*/
DCL &FORMAT *CHAR 8 ('MBRL0200') /* QUSLMBR */
DCL &FIELD *CHAR 30 /* QUSRTVUS */
DCL &MEMBR *CHAR 10
DCL &FILLB *CHAR 20 ('QCLSRC QGPL ')
DCL &MBRNM *CHAR 10 ('*ALL ')
DCL &MTYPE *CHAR 10
DCL &COUNT *DEC (5 0)
CHGVAR %SST(&FILLB 1 10) &FILE
CHGVAR %SST(&FILLB 11 10) &LIB
/*-------------------------------------------------------------------*/
/* Initialize Binary fields and build error return code variable */
/*-------------------------------------------------------------------*/
CHGVAR %BIN(&STARTC) 0
CHGVAR %BIN(&LENGTC) 50000
CHGVAR %BIN(&BYTPV) 8
CHGVAR %BIN(&BYTAV) 0
CHGVAR &DSERR +
( &BYTPV || &BYTAV || &MSGID || &RESVD || &EXDTA)
/*-- Create user space. ---------------------------------------------*/
CALL PGM(QUSCRTUS) PARM(&SPACE &EXTEN &INIT +
&LENGTC &AUTHT &APITX &REPLA &DSERR)
/*-------------------------------------------------------------------*/
/* Call API to load the member names to the user space. */
/*-------------------------------------------------------------------*/
A: CALL PGM(QUSLMBR) PARM(&SPACE &FORMAT &FILLB +
&MBRNM '0' &DSERR)
CHGVAR %BIN(&STARTC) 125
CHGVAR %BIN(&LENGTC) 16
/*-------------------------------------------------------------------*/
/* Call API to return the starting position of the first block, the */
/* length of each data block, and the number of blocks are returned. */
/*-------------------------------------------------------------------*/
CALL PGM(QUSRTVUS) PARM(&SPACE &STARTC &LENGTC +
&STARTN &DSERR)
CHGVAR &ELEMS %BIN(&STARTN 9 4) /* # OF ENTRIES */
IF (&ELEMS = 0) GOTO C /* NO OBJECTS */
CHGVAR &OFSET %BIN(&STARTN 1 4) /* TO 1ST OFFSET */
CHGVAR &LENGT %BIN(&STARTN 13 4) /* LEN OF ENTRIES */
CHGVAR %BIN(&STARTC) (&OFSET + 1)
CHGVAR %BIN(&LENGTC) &LENGT
/*-------------------------------------------------------------------*/
/* Call API to retrieve the data from the user space. &ELEMS */
/* is the number of data blocks to retrieve. Each block contains a */
/* the name of a member. */
/*-------------------------------------------------------------------*/
CHGVAR &COUNT 0
B: CHGVAR &COUNT (&COUNT + 1)
IF (&COUNT *LE &ELEMS) DO
CALL PGM(QUSRTVUS) PARM(&SPACE &STARTC &LENGTC +
&FIELD &DSERR)
CHGVAR &MTYPE %SST(&FIELD 11 10) /* MEMBER TYPE */
CHGVAR &MBRNM %SST(&FIELD 1 10) /* EXTRACT MEMBER NAME */
/* IF (&MTYPE = 'PRTF ') DO */
/* DO YOUR CODE HERE */
SNDPGMMSG MSG(&MBRNM)
/* ENDDO */
CHGVAR &OFSET %BIN(&STARTC)
CHGVAR %BIN(&STARTC) (&OFSET + &LENGT)
GOTO B
ENDDO
C:
DLTUSRSPC USRSPC(QTEMP/LSTOBJR)
ENDPGM
2003-08-06 TCPIP SOCKET RPG 程式範例(Echo server)
TCPIP SOCKET RPG 程式範例(Echo server)
前期電子報介紹 RPG SOCKET 程式的參考資訊,各位先進應該看完了吧。
本期我以一個 Echo server 來當作範例,並提供一隻 echo client rpg 程式讓您測試,
當然您也可以直接利用 telnet 程式測試。
此 Echo server socket 程式啟動後會依照所傳參數(AS/400 host ip 及 port number),
將之 bind 連結到 socket 中,然後 listen 傾聽所指定的 port 有無 client 端連線
需求,如果有就 accept 接受連結,接著傳送連結訊息至 client 端,接著等待 client
輸入任何字串,當 client 端輸入訊息並傳送出去後,Echo server 收到厚利即將原字串
傳回 client 端。當 client 輸入 QUIT 字串時,Echo server 會將此連線中斷,並等待
下一個 client 提出連線需求。
整個流程如下:
Echo Server Echo Client
Create socket Create socket
Bind Bind(可有可無)
Listen
--> Accept <--------- Connect
|
| Send ---------> Receive
| /\ ||
| || \/
| Receive <---------- Send
| "QUIT" "QUIT"
| || ||
| \/ \/
| Close Close
| Client socket
| ||
| \/
------
File : QRPGLESRC
Member: SOCKETSVRR (Echo Server)
Type : RPGLE
Usage : CRTBNDRPG SOCKETSVRR
OS version: V4R1
H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE')
H Debug
D Cmd PR ExtPgm('QCMDEXC')
D command 200A const
D length 15P 5 const
*-------------------------------------------------------------------
* prototype definitions
*-------------------------------------------------------------------
D @__errno PR * ExtProc('__errno')
D strerror PR * ExtProc('strerror')
D errnum 10I 0 value
D perror PR ExtProc('perror')
D comment * value options(*string)
D errno PR 10I 0
*-------------------------------------------------------------------
* socket C API prototype definitions
*-------------------------------------------------------------------
D getservbyname PR * ExtProc('getservbyname')
D service_name * value options(*string)
D protocol_name * value options(*string)
D p_servent S *
D servent DS based(p_servent)
D s_name *
D s_aliases *
D s_port 10I 0
D s_proto *
D inet_addr PR 10U 0 ExtProc('inet_addr')
D address_str * value options(*string)
D INADDR_NONE C CONST(4294967295)
D* any address available
D INADDR_ANY C CONST(0)
D inet_ntoa PR * ExtProc('inet_ntoa')
D internet_addr 10U 0 value
D p_hostent S *
D hostent DS Based(p_hostent)
D h_name *
D h_aliases *
D h_addrtype 10I 0
D h_length 10I 0
D h_addr_list *
D p_h_addr S * Based(h_addr_list)
D h_addr S 10U 0 Based(p_h_addr)
D p_linger S *
D linger DS BASED(p_linger)
D l_onoff 10I 0
D l_linger 10I 0
D gethostbyname PR * extproc('gethostbyname')
D host_name * value options(*string)
D socket PR 10I 0 ExtProc('socket')
D addr_family 10I 0 value
D type 10I 0 value
D protocol 10I 0 value
D AF_INET C CONST(2)
D SOCK_STREAM C CONST(1)
D IPPROTO_IP C CONST(0)
D bind PR 10I 0 ExtProc('bind')
D Sock_Desc 10I 0 Value
D p_Address * Value
D AddressLen 10I 0 Value
D Select PR 10I 0 extproc('select')
D max_desc 10I 0 VALUE
D read_set * VALUE
D write_set * VALUE
D except_set * VALUE
D wait_Time * VALUE
D listen PR 10I 0 ExtProc('listen')
D SocketDesc 10I 0 Value
D Back_Log 10I 0 Value
D accept PR 10I 0 ExtProc('accept')
D Sock_Desc 10I 0 Value
D p_Address * Value
D p_AddrLen 10I 0
D connect PR 10I 0 ExtProc('connect')
D sock_desc 10I 0 value
D dest_addr * value
D addr_len 10I 0 value
D p_sockaddr S *
D sockaddr DS based(p_sockaddr)
D sa_family 5I 0
D sa_data 14A
D sockaddr_in DS based(p_sockaddr)
D sin_family 5I 0
D sin_port 5U 0
D sin_addr 10U 0
D sin_zero 8A
D send PR 10I 0 ExtProc('send')
D sock_desc 10I 0 value
D buffer * value
D buffer_len 10I 0 value
D flags 10I 0 value
D recv PR 10I 0 ExtProc('recv')
D sock_desc 10I 0 value
D buffer * value
D buffer_len 10I 0 value
D flags 10I 0 value
D close PR 10I 0 ExtProc('close')
D sock_desc 10I 0 value
D setsockopt PR 10I 0 ExtProc('setsockopt')
D SocketDesc 10I 0 Value
D Opt_Level 10I 0 Value
D Opt_Name 10I 0 Value
D Opt_Value * Value
D Opt_Len 10I 0 Value
D translate PR ExtPgm('QDCXLATE')
D length 5P 0 const
D data 32766A options(*varsize)
D table 10A const
D die PR
D peMsg 256A const
D* socket layer
D SOL_SOCKET C CONST(-1)
D* re-use local address
D SO_REUSEADDR C 55
D* linger upon close
D SO_LINGER C 30
D msg S 50A
D sock S 10I 0
D port S 5U 0
D addrlen S 10I 0
D ch S 1A
D local s 32A
D localportc s 5A
D IPLocal s 10U 0
D p_bindto S *
D p_Connfrom S *
D lsock S 10I 0
D csock S 10I 0
D RC S 10I 0
D Request S 50A
D ReqLen S 10I 0
D RecBuf S 50A
D RecLen S 10I 0
D on S 10I 0 inz(1)
D err S 10I 0
D clientip S 17A
D line S 80A
D ling S *
D linglen S 10I 0
C*************************************************
C* The user will supply a hostname and port
C* for client connect
C*************************************************
c *entry plist
c parm local
c parm localportc
c eval *inlr = *on
c exsr MakeListener
c dow 1 = 1
c exsr AcceptConn
c exsr TalkToClient
c callp close(csock)
c enddo
C*===============================================================
C* This subroutine sets up a socket to listen for connections
C* include socket, bind, listen API
C*===============================================================
CSR MakeListener begsr
*
C* Get the 32-bit network IP address for
C* local that was supplied by the user:
*
c If local <> *blanks
c eval IPLocal = inet_addr(%trim(local))
c if IPLocal = INADDR_NONE
c eval p_hostent = gethostbyname(%trim(local))
c if p_hostent = *NULL
c callp die('Unable to find that local!')
c return
c endif
c eval IPLocal = h_addr
c endif
c Else
c eval IPlocal = INADDR_ANY
c EndIf
c
c if localportc <> *blanks
c move localportc port
c else
c callp die('Wrong port specified !')
c return
c endif
C* Create a socket
c eval sock = socket(AF_INET: SOCK_STREAM:
c IPPROTO_IP)
c if sock < 0
c callp die('socket(): ' + %str(strerror(errno)))
c return
c endif
C*** Tell socket that we want to be able to re-use the server
C*** port without waiting for the MSL timeout:
c callp setsockopt(sock: SOL_SOCKET:
c SO_REUSEADDR: %addr(on): %size(on))
C* create space for a linger structure
c eval linglen = %size(linger)
c alloc linglen ling
c eval p_linger = ling
C* tell socket to only linger for 2 minutes, then discard:
c eval l_onoff = 1
c eval l_linger = 1
c callp setsockopt(lsock: SOL_SOCKET: SO_LINGER:
c ling: linglen)
C* bind the socket to local port , of any IP address
C* Allocate some space for some socket addresses
c eval addrlen = %size(sockaddr_in)
c alloc addrlen p_bindto
c alloc addrlen p_connfrom
c eval p_sockaddr = p_bindto
c move localportc port
c eval sin_family = AF_INET
c eval sin_addr = IPLocal
c eval sin_port = port
c eval sin_zero = *ALLx'00'
c if bind(sock: p_bindto: addrlen) < 0
c eval err = errno
c callp close(sock)
c callp die('bind(): ' + %str(strerror(err)))
c return
c endif
C* Indicate that we want to listen for connections
c if listen(sock: 5) < 0
c eval err = errno
c callp close(sock)
c callp die('listen(): ' + %str(strerror(err)))
c return
c endif
C
CSR endsr
C*===============================================================
C* This subroutine accepts a new socket connection
C*===============================================================
CSR AcceptConn begsr
C*------------------------
c dou addrlen = %size(sockaddr_in)
C* Accept the next connection.
c eval addrlen = %size(sockaddr_in)
c eval csock = accept(sock: p_connfrom: addrlen)
c if csock < 0
c eval err = errno
c callp close(sock)
c callp die('accept(): ' + %str(strerror(err)))
c return
c endif
C* tell socket to only linger for 2 minutes, then discard:
c eval l_onoff = 1
c eval l_linger = 120
c callp setsockopt(csock: SOL_SOCKET: SO_LINGER:
c ling: linglen)
C* If socket length is not 16, then the client isn't sending the
C* same address family as we are using... that scares me, so
C* we'll kick that guy off.
c if addrlen <> %size(sockaddr_in)
c callp close(csock)
c endif
c enddo
c eval p_sockaddr = p_connfrom
c eval clientip = %str(inet_ntoa(sin_addr))
c clientip dsply
C*------------------------
CSR endsr
C*===============================================================
C* This does a quick little conversation with the connecting
c* client.
C*===============================================================
CSR TalkToClient begsr
C*------------------------
c eval line ='Connection from ' +
c %trim(clientip)
c exsr WrLine
c eval line ='Please enter your name now!'
c exsr WrLine
c eval recbuf = *blanks
c Dow %SubSt(recbuf : 1 : 4) <> 'QUIT'
c exsr RdLine
c If reclen > 0
c eval line = 'Server response: ' + recbuf
c exsr WrLine
c EndIf
c Enddo
c eval line ='Goodbye '
c exsr WrLine
c dealloc(E) p_connfrom
c callp Cmd('DLYJOB DLY(1)': 200)
C*------------------------
CSR endsr
C*===============================================================
C* This subroutine send data to socket client with CRLF
C*===============================================================
CSR WrLine begsr
c eval reqlen = %len(%trim(line))
c callp Translate(reqlen: line: 'QTCPASC')
c eval line = %trim(line) + X'0D0A'
c eval reqlen = %len(%trim(line))
c* 'dmptxt' dump
c eval rc= send(csock: %addr(line): reqlen:0)
c if rc < reqlen
c callp close(csock)
c callp die('Unable to send entire request!')
c return
c endif
CSR endsr
C*===============================================================
C* This subroutine receives what we send to server and
C* displays it on the screen using the DSPLY op-code
C*===============================================================
CSR RdLine begsr
C*------------------------
C*************************************************
C* Receive one line of text from the socket client
C* note that "lines of text" vary in length,
C* but always end with the ASCII values for CR
C* and LF. CR = x'0D' and LF = x'0A'
C*
C* The easiest way for us to work with this data
C* is to receive it one byte at a time until we
C* get the LF character. Each time we receive
C* a byte, we add it to our receive buffer.
C*************************************************
c eval reclen = 0
c eval recbuf = *blanks
c dou reclen = 80 or ch = x'0A'
c eval rc = recv(csock: %addr(ch): 1: 0)
c if rc < 1
c 'rcvfail' dsply
c callp close(csock)
c callp die('Unable to receive data !')
c return
c endif
c if ch<>x'0D' and ch<>x'0A'
c eval reclen = reclen + 1
c eval %subst(recbuf:reclen:1) = ch
c endif
c enddo
C*************************************************
C* translate the line of text into EBCDIC
C* (to make it readable) and display it
C*************************************************
c if reclen > 0
c callp Translate(reclen: recbuf: 'QTCPEBC')
c recbuf dsply
c endif
C*------------------------
Csr endsr
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* This ends this program abnormally, and sends back an escape.
* message explaining the failure.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P die B
D die PI
D peMsg 256A const
D SndPgmMsg PR ExtPgm('QMHSNDPM')
D MessageID 7A Const
D QualMsgF 20A Const
D MsgData 256A Const
D MsgDtaLen 10I 0 Const
D MsgType 10A Const
D CallStkEnt 10A Const
D CallStkCnt 10I 0 Const
D MessageKey 4A
D ErrorCode 32766A options(*varsize)
D dsEC DS
D dsECBytesP 1 4I 0 INZ(256)
D dsECBytesA 5 8I 0 INZ(0)
D dsECMsgID 9 15
D dsECReserv 16 16
D dsECMsgDta 17 256
D wwMsgLen S 10I 0
D wwTheKey S 4A
c eval wwMsgLen = %len(%trimr(peMsg))
c if wwMsgLen<1
c return
c endif
c callp SndPgmMsg('CPF9897': 'QCPFMSG *LIBL':
c peMsg: wwMsgLen: '*ESCAPE':
c '*PGMBDY': 1: wwTheKey: dsEC)
c return
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* This procedure return call socket C API errno
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P errno B
D errno PI 10I 0
D p_errno S *
D wwreturn S 10I 0 based(p_errno)
C eval p_errno = @__errno
c return wwreturn
P E
File : QRPGLESRC
Member: SOCKETCLTR (Echo Client)
Type : RPGLE
Usage : CRTBNDRPG SOCKETCLTR
OS version: V4R1
H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE')
H Debug
*-------------------------------------------------------------------
* prototype definitions
*-------------------------------------------------------------------
D @__errno PR * ExtProc('__errno')
D strerror PR * ExtProc('strerror')
D errnum 10I 0 value
D perror PR ExtProc('perror')
D comment * value options(*string)
D errno PR 10I 0
*-- Sleep --- Sleep function (delay job) ------------------------
* unsigned int sleep( unsigned int seconds );
D sleep Pr 10U 0 ExtProc('sleep')
D 10U 0 Value
* socket C API prototype definitions
*-------------------------------------------------------------------
D getservbyname PR * ExtProc('getservbyname')
D service_name * value options(*string)
D protocol_name * value options(*string)
D p_servent S *
D servent DS based(p_servent)
D s_name *
D s_aliases *
D s_port 10I 0
D s_proto *
D inet_addr PR 10U 0 ExtProc('inet_addr')
D address_str * value options(*string)
D INADDR_NONE C CONST(4294967295)
D inet_ntoa PR * ExtProc('inet_ntoa')
D internet_addr 10U 0 value
D p_hostent S *
D hostent DS Based(p_hostent)
D h_name *
D h_aliases *
D h_addrtype 10I 0
D h_length 10I 0
D h_addr_list *
D p_h_addr S * Based(h_addr_list)
D h_addr S 10U 0 Based(p_h_addr)
D gethostbyname PR * extproc('gethostbyname')
D host_name * value options(*string)
D socket PR 10I 0 ExtProc('socket')
D addr_family 10I 0 value
D type 10I 0 value
D protocol 10I 0 value
D AF_INET C CONST(2)
D SOCK_STREAM C CONST(1)
D IPPROTO_IP C CONST(0)
D bind PR 10I 0 ExtProc('bind')
D Sock_Desc 10I 0 Value
D p_Address * Value
D AddressLen 10I 0 Value
D connect PR 10I 0 ExtProc('connect')
D sock_desc 10I 0 value
D dest_addr * value
D addr_len 10I 0 value
D p_sockaddr S *
D sockaddr DS based(p_sockaddr)
D sa_family 5I 0
D sa_data 14A
D sockaddr_in DS based(p_sockaddr)
D sin_family 5I 0
D sin_port 5U 0
D sin_addr 10U 0
D sin_zero 8A
D send PR 10I 0 ExtProc('send')
D sock_desc 10I 0 value
D buffer * value
D buffer_len 10I 0 value
D flags 10I 0 value
D recv PR 10I 0 ExtProc('recv')
D sock_desc 10I 0 value
D buffer * value
D buffer_len 10I 0 value
D flags 10I 0 value
D close PR 10I 0 ExtProc('close')
D sock_desc 10I 0 value
D setsockopt PR 10I 0 ExtProc('setsockopt')
D SocketDesc 10I 0 Value
D Opt_Level 10I 0 Value
D Opt_Name 10I 0 Value
D Opt_Value * Value
D Opt_Len 10I 0 Value
D translate PR ExtPgm('QDCXLATE')
D length 5P 0 const
D data 32766A options(*varsize)
D table 10A const
D die PR
D peMsg 256A const
D* socket layer
D SOL_SOCKET C CONST(-1)
D* re-use local address
D SO_REUSEADDR C 55
D msg S 50A
D sock S 10I 0
D port S 5U 0
D addrlen S 10I 0
D ch S 1A
D host s 32A
D hostportc s 5A
D local s 32A
D localportc s 5A
D IPHost s 10U 0
D IPLocal s 10U 0
D p_bindto S *
D p_Connto S *
D RC S 10I 0
D Request S 50A
D ReqLen S 10I 0
D RecBuf S 50A
D RecLen S 10I 0
D on S 10I 0 inz(1)
D err S 10I 0
C*************************************************
C* The user will supply a hostname and file
C* name as parameters to our program...
C*************************************************
c *entry plist
c parm host
c parm hostportc
c parm local
c parm localportc
c eval *inlr = *on
c exsr SktCnn
c exsr TalkToSktSvr
C*************************************************
C* SOCKET CONNECTION
C*************************************************
C SktCnn BegSr
C*************************************************
C* Get the 32-bit network IP address for the host
C* & local that was supplied by the user:
C*************************************************
c eval IPHost = inet_addr(%trim(host))
c if IPHost = INADDR_NONE
c eval p_hostent = gethostbyname(%trim(host))
c if p_hostent = *NULL
c callp die('Unable to find that host!')
c return
c endif
c eval IPHost = h_addr
c endif
c If local <> *blanks
c eval IPLocal = inet_addr(%trim(local))
c if IPLocal= INADDR_NONE
c eval p_hostent = gethostbyname(%trim(local))
c if p_hostent = *NULL
c callp die('Unable to find that local!')
c return
c endif
c eval IPLocal = h_addr
c endif
c endif
C*************************************************
C* Create a socket
C*************************************************
c eval sock = socket(AF_INET: SOCK_STREAM:
c IPPROTO_IP)
c if sock < 0
c callp die('socket(): ' + %str(strerror(errno)))
c return
c endif
C*** Tell socket that we want to be able to re-use the server
C*** port without waiting for the MSL timeout:
c callp setsockopt(sock: SOL_SOCKET:
c SO_REUSEADDR: %addr(on): %size(on))
C if local <> *blanks And
C localportc <> *blanks
C* bind the socket to local port , of any IP address
C* Allocate some space for some socket addresses
c eval addrlen = %size(sockaddr_in)
c alloc addrlen p_bindto
c eval p_sockaddr = p_bindto
c move localportc port
c eval sin_family = AF_INET
c eval sin_addr = IPLocal
c eval sin_port = port
c eval sin_zero = *ALLx'00'
c if bind(sock: p_bindto: addrlen) < 0
c eval err = errno
c callp close(sock)
c callp die('bind(): ' + %str(strerror(err)))
c return
c endif
c endif
C*************************************************
C* Create a socket address structure that
C* describes the host & port we wanted to
C* connect to
C*************************************************
c eval addrlen = %size(sockaddr)
c alloc addrlen p_connto
c eval p_sockaddr = p_connto
c move hostportc port
c eval sin_family = AF_INET
c eval sin_addr = IPHost
c eval sin_port = port
c eval sin_zero = *ALLx'00'
C*************************************************
C* Connect to the requested host
C*************************************************
C if connect(sock: p_connto: addrlen) < 0
c eval err = errno
c callp close(sock)
c callp die('Connect(): ' + %str(strerror(err)))
c return
c endif
C EndSr
C*************************************************
C* TALK TO SOCKET SERVER
C*************************************************
C TalktoSktSvr BegSr
C*************************************************
C* Format a request and tralslate to ASCII and
C* send to socket server depend on your purpose
C*************************************************
C Dow *In99 = *Off
* once connect , receive socket server
* two welcome message
c N90 do 2
C exsr RecvResponse
c eval *In90 = *on
c enddo
* input anything you want
c clear request
c 'Input String'Dsply
c Dsply request
c eval reqlen = %len(%trim(request))
c If reqlen = 0
c iter
c EndIf
c If %SubSt(request : 1 : 4) = 'QUIT'
c eval *In99 = *On
c EndIf
c* eval request = 'Any data to send to socket server'
c callp Translate(reqlen: request: 'QTCPASC')
C*************************************************
c* Append ASCII X'0D0A' to request means end of
C* line and send the request to the socket server
C*************************************************
c eval request = %trim(request) + X'0D0A'
c eval reqlen = %len(%trim(request))
c eval rc = send(sock: %addr(request): reqlen:0)
c if rc < reqlen
c callp close(sock)
c callp die('Unable to send entire request!')
c return
c endif
c* 'sended' dsply
C exsr RecvResponse
C*************************************************
C* Get back the server's response
C*************************************************
C enddo
* get 'GoodBye' message
C exsr RecvResponse
C*************************************************
C* We're done, so close the socket.
C* do a dsply with input to pause the display
C* and then end the program
C*************************************************
c callp close(sock)
c dsply pause 1
c return
C EndSr
C*===============================================================
C* This subroutine receives what we send to server and
C* displays it on the screen using the DSPLY op-code
C*===============================================================
CSR RecvResponse begsr
C*------------------------
C*************************************************
C* Receive one line of text from the socket server.
C* note that "lines of text" vary in length,
C* but always end with the ASCII values for CR
C* and LF. CR = x'0D' and LF = x'0A'
C*
C* The easiest way for us to work with this data
C* is to receive it one byte at a time until we
C* get the LF character. Each time we receive
C* a byte, we add it to our receive buffer.
C*************************************************
c eval reclen = 0
c eval recbuf = *blanks
c dou reclen = 50 or ch = x'0A'
c eval rc = recv(sock: %addr(ch): 1: 0)
c if rc < 1
c leave
c endif
c if ch<>x'0D' and ch<>x'0A'
c eval reclen = reclen + 1
c eval %subst(recbuf:reclen:1) = ch
c endif
c enddo
C*************************************************
C* translate the line of text into EBCDIC
C* (to make it readable) and display it
C*************************************************
c if reclen > 0
c callp Translate(reclen: recbuf: 'QTCPEBC')
c endif
c recbuf dsply
C*------------------------
Csr endsr
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* This ends this program abnormally, and sends back an escape.
* message explaining the failure.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P die B
D die PI
D peMsg 256A const
D SndPgmMsg PR ExtPgm('QMHSNDPM')
D MessageID 7A Const
D QualMsgF 20A Const
D MsgData 256A Const
D MsgDtaLen 10I 0 Const
D MsgType 10A Const
D CallStkEnt 10A Const
D CallStkCnt 10I 0 Const
D MessageKey 4A
D ErrorCode 32766A options(*varsize)
D dsEC DS
D dsECBytesP 1 4I 0 INZ(256)
D dsECBytesA 5 8I 0 INZ(0)
D dsECMsgID 9 15
D dsECReserv 16 16
D dsECMsgDta 17 256
D wwMsgLen S 10I 0
D wwTheKey S 4A
c eval wwMsgLen = %len(%trimr(peMsg))
c if wwMsgLen<1
c return
c endif
c callp SndPgmMsg('CPF9897': 'QCPFMSG *LIBL':
c peMsg: wwMsgLen: '*ESCAPE':
c '*PGMBDY': 1: wwTheKey: dsEC)
c return
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* This procedure return call socket C API errno
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P errno B
D errno PI 10I 0
D p_errno S *
D wwreturn S 10I 0 based(p_errno)
C eval p_errno = @__errno
c return wwreturn
P E
執行方式:
1. 執行 Echo server
SBMJOB CMD(CALL SOCKETSVRR('your-as/400-ip' 'port')) JOB(SOCKETSVR)
or
SBMJOB CMD(CALL PGM(SOCKETSVRR) PARM('172.16.15.35' '04000')) JOB(SOCKETSR)
2. 執行 Echo client
CALL PGM(SOCKETcltR) PARM('your-as/400 ip' 'port' 'local-as/400 ip' 'local port')
or
CALL PGM(SOCKETCLTR) PARM('172.16.15.35' '04000' '172.16.15.35' '21000')
or
在 PC DOS 視窗上執行 telnet AS/400IPAddress PORT
telnet AS/400IP PORT
telnet 172.16.15.35 4000
本 Echo server 範例程式目前僅做 ASCII, EBCDIC 轉換,位支援 big5 中文轉換,
你可以使用 API iconv() 或 API QDCXLATE 轉換,或自行轉碼。 相關轉碼請參閱:
http://publib.boulder.ibm.com/iseries/v5r1/ic2924/info/apis/iconv.htm
http://publib.boulder.ibm.com/iseries/v5r1/ic2924/index.htm?info/apis/QDCXLATE.htm
2003-07-29 如何利用 RPG 寫 TCP/IP Socket 程式 ?
如何利用 RPG 寫 TCP/IP Socket 程式 ?
要利用 RPG 寫 TCP/IP socket 程式,則需要透過呼叫 C 的相關 API,與 TCP/IP 相關的
C API 詳細表列於
https://www.ibm.com/docs/en/i/7.5?topic=communications-socket-programming
Sockets APIs system functions
https://www.ibm.com/docs/en/i/7.5?topic=ssw_ibm_i_75/apis/unix8a.html
Sockets APIs network functions
https://www.ibm.com/docs/en/i/7.5?topic=ssw_ibm_i_75/apis/unix8b.html
若想要了解 Socket 程式設計請參考 Sockets Programming,此連結文件包含所有相關紅皮書及 Socket 的觀念。
紅皮書 Who Knew You Could Do That with RPG IV? A Sorcerer's Guide to System Access and More.
http://www.redbooks.ibm.com/abstracts/sg245402.html
章節 5.5 詳細說明如何利用 RPG 撰寫 Socket 程式。請自行下載參考。
一個非常好的 RPG socket 工具:
RPG IV Sockets Tutorial
https://www.scottklement.com/rpg/socktut/index.html
內含教育手冊及 SAVF 範例。可以將 SAVF 上傳至 AS/400,
再 restore,內含許多範例。
2003-06-10 如何動態選取要儲存的物件或原始檔成員(TFROBJ) ?
如何動態選取要儲存的物件或原始檔成員(TFROBJ) ?
有時候由於檔案或原始檔某些成員需要傳至另一個 AS/400(iSeries) 系統,
所以需要使用 SAVOBJ 的方式儲存,但是又須麻煩的一個一個輸入指定物件或原
始檔成員,所以我寫一個程式針對同一個 Library 中的物件或原始檔中
成員讓使用者選取,並將所選儲存至同一 Library SAVF 中,然後你可以
使用此 SAVF 利用 FTP 或 SNDNETF 或 SAVRSTOBJ 傳輸至另一系統中。
此程式中使用 Source-Library -> 欲儲存的 Library
Targrt-Library -> 欲 Restored 到目的地 Library,目前未使用,若需要將傳輸及自動 Restored 時,你可以利用此參數。
二個參數,並將選取的物件存至 Source-Library 中以同 Source-Library 為名的 SAVF。
File : QCLSRC
Member: TFROBJC
Type : CLP
Usage : CRTCLPGM TFROBJC
PGM (&SRCLIB &TOLIB)
DCL VAR(&SRCLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&TOLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&SAVOBJTYP) TYPE(*CHAR) LEN(10)
DCL VAR(&CURRCD) TYPE(*DEC) LEN(10 0)
DCLF QAFDBASI
/* OUTPUT OBJ DESCRIPTION TO OUTFILE */
DSPOBJD OBJ(&SRCLIB/*ALL) OBJTYPE(*ALL) +
OUTPUT(*OUTFILE) OUTFILE(QTEMP/DSPOBJ)
/* OUTPUT FILE DESCRIPTION TO OUTFILE */
DSPFD FILE(&SRCLIB/*ALL) TYPE(*BASATR) +
OUTPUT(*OUTFILE) OUTFILE(QTEMP/DSPFD)
OVRDBF FILE(QAFDBASI) TOFILE(QTEMP/DSPFD)
DLTF DSPMBRLIST
MONMSG CPF0000
NEXT:
RCVF
MONMSG CPF0864 EXEC(GOTO MBRLISTEND)
IF (&ATDTAT = 'S') +
DSPFD FILE(&ATLIB/&ATFILE) TYPE(*MBRLIST) +
OUTPUT(*OUTFILE) +
OUTFILE(QTEMP/DSPMBRLIST) OUTMBR(*FIRST *ADD)
GOTO NEXT
MBRLISTEND:
DLTF QTEMP/SAVMBRLIST
MONMSG CPF0000
/* CREATE TEMP FILE TO SAVE SAVED MEMBER NAME AND OBJ */
CRTDUPOBJ OBJ(QAFDMBRL) FROMLIB(*LIBL) OBJTYPE(*FILE) +
TOLIB(QTEMP) NEWOBJ(SAVMBRLIST)
ADDPFM FILE(QTEMP/SAVMBRLIST) MBR(SAVMBRLIST)
/* SELECT OBJECT TO SAVED */
CALL TFROBJR
/* CONSTRUCT SAVRST COMMAND */
RTVMBRD FILE(QTEMP/SAVMBRLIST) NBRCURRCD(&CURRCD)
IF (&CURRCD > 0) +
CALL TFROBJC1 (&SRCLIB &TOLIB)
ENDPGM
File : QCLSRC
Member: TFROBJC1
Type : CLP
Usage : CRTCLPGM TFROBJC1
PGM (&SRCLIB &TOLIB)
DCL VAR(&SRCLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&TOLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&SAVOBJTYP) TYPE(*CHAR) LEN(10)
DCL VAR(&CMDSTR) TYPE(*CHAR) LEN(3000) +
VALUE('SAVOBJ OBJ(')
DCL VAR(&MLFILES) TYPE(*CHAR) LEN(10) +
VALUE(' ')
DCL VAR(&SAVFILE) TYPE(*CHAR) LEN(10)
DCL VAR(&SAVOBJS) TYPE(*CHAR) LEN(7) +
VALUE('SAVOBJ ')
DCL VAR(&OBJS) TYPE(*CHAR) LEN(4) VALUE('OBJ(')
DCL VAR(&OBJSS) TYPE(*CHAR) LEN(150)
DCL VAR(&LIBS) TYPE(*CHAR) LEN(4) VALUE('LIB(')
DCL VAR(&DEVS) TYPE(*CHAR) LEN(11) +
VALUE('DEV(*SAVF) ')
DCL VAR(&OBJTYPS) TYPE(*CHAR) LEN(14) +
VALUE('OBJTYPE(*ALL) ')
DCL VAR(&SAVFS) TYPE(*CHAR) LEN(15) VALUE('SAVF(')
DCL VAR(&FILEMBRS) TYPE(*CHAR) LEN(15) +
VALUE('FILEMBR(')
DCL VAR(&LEFT) TYPE(*CHAR) LEN(1) VALUE('(')
DCL VAR(&RIGHT) TYPE(*CHAR) LEN(2) VALUE(') ')
DCL VAR(&SLASH) TYPE(*CHAR) LEN(1) VALUE('/')
DCL VAR(&MBRS) TYPE(*CHAR) LEN(300)
DCL VAR(&WITHMBRS) TYPE(*CHAR) LEN(1)
DCLF QAFDMBRL
CHGVAR &SAVFILE &SRCLIB
DLTF &SRCLIB/&SAVFILE
MONMSG CPF0000
CRTSAVF FILE(&SRCLIB/&SAVFILE)
OVRDBF FILE(QAFDMBRL) TOFILE(QTEMP/SAVMBRLIST)
NEXT:
RCVF
MONMSG CPF0864 EXEC(GOTO MBRLISTEND)
IF (&MLFILES *NE &MLFILE) DO
/* SAVOBJ +
OBJ(FILE) LIB(SRCLIB) DEV(*SAVF) +
OBJTYPE(*FILE) SAVF(SRCLIB/SAVF) +
FILEMBR((FILE1 (MBR1 MBR2)) (FILE2 (MBR1 +
MBR2))) */
IF (&MLFILES *NE ' ' *AND +
&MLNAME *NE ' ') DO
CHGVAR &MBRS +
(&MBRS *TCAT &RIGHT *TCAT &RIGHT)
ENDDO
CHGVAR &MLFILES &MLFILE
CHGVAR &OBJSS (&OBJSS *BCAT &MLFILE)
IF (&MLNAME *NE ' ') DO
CHGVAR &MBRS +
(&MBRS *BCAT &LEFT *CAT &MLFILE *BCAT &LEFT)
CHGVAR &WITHMBRS '1'
ENDDO
ENDDO
IF (&MLNAME *NE ' ') +
CHGVAR &MBRS +
(&MBRS *BCAT &MLNAME)
GOTO NEXT
MBRLISTEND:
DLTOVR FILE(*ALL)
CHGVAR &CMDSTR +
(&SAVOBJS *CAT +
&OBJS *TCAT &OBJSS *TCAT &RIGHT *CAT +
&LIBS *TCAT &MLLIB *TCAT &RIGHT *CAT +
&DEVS *CAT +
&OBJTYPS *CAT +
&SAVFS *TCAT &SRCLIB *TCAT &SLASH *CAT +
&SAVFILE *TCAT &RIGHT)
CHGVAR &MBRS +
(&MBRS *TCAT &RIGHT *TCAT &RIGHT *TCAT &RIGHT)
IF (&WITHMBRS = '1') DO
CHGVAR &CMDSTR +
(&CMDSTR *BCAT &FILEMBRS *CAT &MBRS)
ENDDO
CALL QCMDEXC (&CMDSTR 3000)
SNDPGMMSG MSG('SAVF' *BCAT &SAVFILE *BCAT 'created in' +
*BCAT &SRCLIB *TCAT '.') TOPGMQ(*PRV +
(TFROBJC))
ENDPGM
File : QDDSSRC
Member: TFROBJD
Type : DSPF
Usage : CRTDSPF TFROBJD
*===============================================================
*
* To compile:
*
* CRTDSPF FILE(XXX/TFROBJD) SRCFILE(XXX/QDDSSRC)
*
*===============================================================
A*
A*%%EC
A DSPSIZ(24 80 *DS3)
A PRINT
A ERRSFL
A CA03
A CA12
A*
A R SFL1 SFL
A*
A SELECT 1 B 6 2
A MLFILE 10 O 6 4
A MLNAME 10 O 6 15
A MLCDAT 6 O 6 26
A MLCHGD 6 O 6 33
A ODOBNM 10 O 6 40
A ODOBTP 8 O 6 51
A ODOBOW 10 O 6 60
A ODLDAT 6 O 6 71
A ODCDAT 6 H
A*
A*
A R SF1CTL SFLCTL(SFL1)
A SFLSIZ(0017)
A SFLPAG(0016)
A OVERLAY
A N32 SFLDSP
A N31 SFLDSPCTL
A 31 SFLCLR
A 90 SFLEND(*MORE)
A SFLCSRRRN(&CSRRRN1)
A RRN1 4S 0H SFLRCDNBR
A CSRRRN1 5S 0H
A 1 2'TFROBJR '
A 1 28'Your Company name'
A COLOR(WHT)
A 1 71DATE
A EDTCDE(Y)
A 2 29'Select Object or SRC Member to save'
A COLOR(WHT)
A 2 71TIME
A 3 1'X'
A 4 3'LIBRARY:'
A SAVLIB 10 O 4 12
A 5 4'FILE'
A COLOR(WHT)
A 5 15'MEMBER'
A COLOR(WHT)
A 4 26'CRT'
A COLOR(WHT)
A 5 26'DATE'
A COLOR(WHT)
A 3 33'LAST'
A COLOR(WHT)
A 4 33'CHANGE'
A COLOR(WHT)
A 5 33'DATE'
A COLOR(WHT)
A 5 40'OBJECT'
A COLOR(WHT)
A 5 51'TYPE'
A COLOR(WHT)
A 5 60'OWNER'
A COLOR(WHT)
A 3 71'LAST'
A COLOR(WHT)
A 4 71'CHANGED'
A COLOR(WHT)
A 5 71'DATE'
A COLOR(WHT)
A*
A R SFL2 SFL
A*
A SELECT 1 B 6 2
A ODLBNM 10 O 6 4
A ODOBNM 10 O 6 15
A ODOBTP 8 O 6 26
A ODOBAT 10 O 6 37
A ODCDAT 6 O 6 48
A ODLDAT 6 O 6 55
A ODOBOW 10 O 6 62
A R SF2CTL SFLCTL(SFL2)
A SFLSIZ(0017)
A SFLPAG(0016)
A OVERLAY
A N32 SFLDSP
A N31 SFLDSPCTL
A 31 SFLCLR
A 90 SFLEND(*MORE)
A RRN2 4S 0H
A 1 2'TFROBJR '
A 1 28'Your Company name'
A COLOR(WHT)
A 1 71DATE
A EDTCDE(Y)
A 2 34''
A COLOR(WHT)
A 2 71TIME
A 3 1'X'
A 5 4'LIBRARY'
A COLOR(WHT)
A 5 15'OBJECT '
A COLOR(WHT)
A 5 26'OBJTYPE'
A COLOR(WHT)
A 5 37'ATTR'
A COLOR(WHT)
A 4 48'CRT'
A COLOR(WHT)
A 5 48'DATE'
A COLOR(WHT)
A 4 48'CHG'
A COLOR(WHT)
A 5 55'DATE'
A COLOR(WHT)
A 5 62'OWNER'
A COLOR(WHT)
A R SFL3 SFL
A SAVOBJ 10 O 6 4
A SAVMBR 10 O 6 15
A MLCDAT 6 O 6 27
A MLCHGD 6 O 6 34
A ODOBOW 10 O 6 41
*
A R SF3CTL SFLCTL(SFL3)
A SFLSIZ(0017)
A SFLPAG(0016)
A OVERLAY
A N32 SFLDSP
A N31 SFLDSPCTL
A 31 SFLCLR
A 90 SFLEND(*MORE)
A RRN3 4S 0H
A 1 2'TFROBJR '
A 1 28'Your Company Name'
A COLOR(WHT)
A 1 71DATE
A EDTCDE(Y)
A 2 34'Confirm Selection'
A 2 71TIME
A 3 1'Please press Enter to confirm'
A 4 3'LIBRARY:'
A SAVLIB 10 O 4 12
A 5 4'OBJECT MEMBER'
A COLOR(WHT)
A 4 27'CRT'
A COLOR(WHT)
A 5 27'DATE'
A COLOR(WHT)
A 3 34'LAST'
A COLOR(WHT)
A 4 34'CHG'
A COLOR(WHT)
A 5 34'DATE'
A COLOR(WHT)
A 5 41'OWNER'
A COLOR(WHT)
A R FKEY1
A*
A 23 2'F3=Exit'
A COLOR(BLU)
A 23 12'F12=Cancel'
A COLOR(BLU)
File : QRPGLESRC
Member: TFROBJR
Type : RPGLE
Usage : CRTBNDRPG TFROBJR
*===============================================================
*
* To compile:
*
* CRTBNDRPG PGM(XXX/TFROBJR) SRCFILE(XXX/QRPGLESRC)
*
*===============================================================
H DEBUG OPTION(*SRCSTMT:*NODEBUGIO)
H DftActGrp(*NO) ActGrp(*CALLER)
FTFROBJD cf e workstn
F sfile(sfl1:rrn1)
F sfile(sfl2:rrn2)
F sfile(sfl3:rrn3)
F infds(info)
FDSPOBJ if e disk
FDSPMBRLISTif e disk
FSAVMBRLISTO e disk rename(QWHFDML : SAVMBRR)
* Information data structure to hold attention indicator (AID) byte.
* AID byte contains a code identifying the function
* key used to return control to the program from the display file.
* For more information see the DATA MANAGEMENT GUIDE.
Dinfo ds
D cfkey 369 369
* Constants to compare to AID - F3, F12, F6, and ENTER keys.
* Other values documented in DATA MANAGEMENT GUIDE.
Dexit C const(X'33')
Dcancel C const(X'3C')
Dadd C const(X'36')
Denter C const(X'F1')
* Input parameter: Source Type or not
D savrrn S 5S 0
D confirm S 1
* Clear the subfile, then call the recursive NextLevel procedure
C ExSr clrsfl
C Exsr loadsfl
C Eval *In90 = *on
C If rrn1 = 0
C Eval *in32 = *on
C EndIf
C* Eval csrrrn1 = 1
* Simply redisplay subfile until user hits Exit or Cancel
C DoU (cfkey = exit) or (cfkey = cancel)
C Write fkey1
C ExFmt sf1ctl
C Exsr prcsfl
C If confirm = '1'
C leave
C EndIf
C EndDo
* Close files and terminate.
C Eval *inlr = *on
*********************************************************************
C ClrSfl BegSr
* Clear the subfile by activating SFLCLR and writing the subfile control
* format. Reset the subfile relative record number.
C Eval *in31 = *on
C Eval rrn1 = 0
C Write sf1ctl
C Eval *in31 = *off
*
C EndSr
*********************************************************************
C Loadsfl Begsr
* Loop until EOF is encountered.
* read DSPMBRLIST
C Read DSPMBRLIST
C DoW not %eof
C Eval select = ' '
* Update the global RRN counter, and write the new subfile record.
C Eval rrn1 = rrn1 + 1
C Write sfl1
C Read DSPMBRLIST
C EndDo
C Eval SAVLIB = MLLIB
* read DSPOBJ
C Reset SFL1
C Read DSPOBJ
C DoW not %eof
C Eval select = ' '
* Update the global RRN counter, and write the new subfile record.
C Eval rrn1 = rrn1 + 1
C Write sfl1
C Read DSPOBJ
C EndDo
C Eval savrrn = rrn1
C Eval rrn1 = 1
C EndSr
*********************************************************************
C PrcSfl Begsr
* clear sfl3
C Eval *in31 = *on
C Eval rrn3 = 0
c Write sf3ctl
C Eval *in31 = *off
C z-add 1 idx 5 0
C Eval confirm = '0'
C DoW idx < savrrn
C idx Chain sfl1
C If select = 'X'
C If MLFILE <> *blanks
C Eval SavLIB = SAVLIB
C Eval SavOBJ = MLFILE
C Eval SavMBR = MLNAME
C Else
C Eval SavLIB = SAVLIB
C Eval SavOBJ = ODOBNM
C Eval SavMBR = *BLANKS
C Eval MLCDAT = ODCDAT
C Eval MLCHGD = ODLDAT
C EndIf
C Z-add idx strrrn 4 0
C Eval rrn3 = rrn3 + 1
C Write sfl3
C Eval select = ' '
C update sfl1
C EndIf
C Eval idx = idx + 1
C EndDo
C
C If rrn3 > 0
C z-add rrn3 savrrn3 4 0
C Write fkey1
C ExFmt sf3ctl
C If (cfkey <> exit) and (cfkey <> cancel)
C Eval confirm = '1'
C Eval idx = 1
C Reset SAVMBRR
C DoW idx <= savrrn3
C idx Chain sfl3
C Eval MLLIB = SAVLIB
C Eval MLFILE= SAVOBJ
C EVAL MLNAME= SAVMBR
C EVAL MLSEU2= ODOBOW
C Write SAVMBRR
C Eval idx = idx + 1
C EndDo
C EndIf
C EndIf
C If strrrn > 0
C Z-add strrrn rrn1
C Else
C Z-add csrrrn1 rrn1
C EndIf
C EndSr
由於此程式利用 QTEMP 暫存檔處理,所以安裝程序須照下列方式,否則無法編譯完成:
1. 將 TFROBJC 程式後段修改如下:
/* SELECT OBJECT TO SAVED */
/* CALL TFROBJR */
/* CONSTRUCT SAVRST COMMAND */
/* RTVMBRD FILE(QTEMP/SAVMBRLIST) NBRCURRCD(&CURRCD) */
/* IF (&CURRCD > 0) + */
/* CALL TFROBJC1 (&SRCLIB &TOLIB) */
儲存,執行編譯 CRTCLPGM TFROBJC完成後,
執行 CALL TFROBJC ('QGPL' 'QGPL' '*ALL')產生暫存檔 QTEMP/SAVMBRLIST 供 TFROBJR 使用。
2. CRTDSPF TFROBJD
3. CRTBNDRPG TFROBJR
4. CRTCLPGM TFROBJC1
5. 回復 TFROBJC 後段為:
/* SELECT OBJECT TO SAVED */
CALL TFROBJR
/* CONSTRUCT SAVRST COMMAND */
RTVMBRD FILE(QTEMP/SAVMBRLIST) NBRCURRCD(&CURRCD)
IF (&CURRCD > 0) +
CALL TFROBJC1 (&SRCLIB &TOLIB)
儲存,執行編譯 CRTCLPGM TFROBJC 完成安裝。
執行程式語法:
CALL TFROBJC ('source-library' 'target-library')
2003-05-30 如何取得系統現在有幾個線上使用者(Users currently signed on)?
如何取得系統現在有幾個線上使用者(Users currently signed on)?
可以利用 System API QWCRSSTS 取得系統現有狀態,此 API 包含的資訊與 DSPSYSSTS
指令所顯示的資訊是類似的,更包括記憶體區塊的使用情形。
詳細請參考 :
Retrieve System Status (QWCRSSTS) API
http://publib.boulder.ibm.com/iseries/v5r2/ic2924/info/apis/qwcrssts.htm
File : QCLSRC
Member: RTVSIGNONC
Type : CLP
Usage : CRTCLPGM RTVSIGNONC
CALL RTVSIGNONC
/* Program : RTVSIGNONC */
/* System : iSeries */
/* */
/* Description : retrieve the number of users signed on */
/* */
PGM
DCL VAR(&SIGNON) TYPE(*DEC) LEN(9 0)
DCL VAR(&SIGNON_CHR) TYPE(*CHAR) LEN(9)
DCL VAR(&RECEIVER) TYPE(*CHAR) LEN(100)
DCL VAR(&RCV_LEN) TYPE(*CHAR) LEN(4)
DCL var(&RESET) TYPE(*CHAR) LEN(10)
CHGVAR VAR(%BIN(&RCV_LEN)) VALUE(100)
CHGVAR VAR(&RESET) VALUE('*NO')
CALL PGM(QWCRSSTS) PARM(&RECEIVER &RCV_LEN +
'SSTS0100' &RESET X'00000000')
CHGVAR VAR(&SIGNON) VALUE(%BIN(&RECEIVER 25 4))
CHGVAR VAR(&SIGNON_CHR) VALUE(&SIGNON)
SNDPGMMSG MSG('The number of users signed on = ' *CAT +
&SIGNON_CHR)
END: ENDPGM
2003-05-14 如何跨 AS/400 系統間快速即時傳送原始檔成員(source member)?(SNDSRC)
2003-05-14 如何跨 AS/400 系統間快速即時傳送原始檔成員(source member)?(SNDSRC)
由於一般公司有可能將開發測試與應用軟體正式運行的環境分成不同的機器,所以時常
會有傳送程式或畫面原始檔需求,一般若是要傳送的原始檔成員很多時均是使用磁帶,Send
Network File(SNA網路) 或 FTP(TCP/IP網路)方式,但是若要傳送的原始檔成員不多時,
可考慮使用 DDMF 方式,DDMF 支援 SNA(適合所有 OS/400 版本) 及 TCP/IP網路(適合
所有 OS/400 V4R4 以後版本) 。 您可依自己系統的需求設定採用哪一種方式。在此範例
採用 TCP/IP 網路。
File : QCLSRC
Member: SNDSRCD
Type : DSPF
Usage : CRTDSPF SNDSRCD
A DSPSIZ(24 80 *DS3)
A PRINT
A R SNDFMT
A CF03(03 'EXIT')
A CF12(12 'CANCEL')
A OVERLAY
A 1 32'Send Source Member'
A DSPATR(HI)
A 3 2'From File . . . . . . . :'
A FRMFIL 10A O 3 30
A 4 4'From Library. . . . . :'
A FRMLIB 10A O 4 32
A 7 2'Type the file name, library, and s-
A ystem to receive the source member.'
A COLOR(BLU)
A 9 4'To File . . . . . . . :'
A TOFIL 10A B 9 30
A 50 DSPATR(PC)
A 50 DSPATR(RI)
A 10 6'To Library . . . . :'
A TOLIB 10A B 10 32
A 51 DSPATR(RI)
A 51 DSPATR(PC)
A 5 8'From System . . . :'
A TOSYS 8A B 11 34
A 52 DSPATR(RI)
A 52 DSPATR(PC)
A 13 2'To rename copied member, type New -
A Name, press Enter.'
A COLOR(BLU)
A 15 2'Member'
A DSPATR(HI)
A 15 17'New Name'
A DSPATR(HI)
A FRMMBR 10A O 16 2
A TOMBR 10A B 16 17
A 53 DSPATR(RI)
A 53 DSPATR(PC)
A 11 8'To System . . . . :'
A FRMSYS 8A O 5 34
A R MSGSFL SFL
A SFLMSGRCD(24)
A MSGKEY SFLMSGKEY
A PGMQ SFLPGMQ(10)
A*/
A R MSGCTL SFLCTL(MSGSFL)
A OVERLAY
A SFLSIZ(0050)
A SFLPAG(0001)
A SFLDSP
A SFLDSPCTL
A SFLINZ
A N99 SFLEND
A PGMQ SFLPGMQ(10)
A 23 2'F3=Exit'
A COLOR(BLU)
A 23 11'F12=Cancel'
A COLOR(BLU)
File : QCLSRC
Member: SNDSRCC
Type : CLP
Usage :
1. 修改此程式參數 SYSTEM1 及 SYSTEM2 為 AS/400 的系統名稱(SNA device remote location)
或 IP 主機名稱或 IP 位址。此範例是使用 IP IP 主機名稱(定義於 CFGTCP 選項 10 中)
2. CRTCLPGM SNDSRCC
3. STRPDM 選 9 --> 執行鍵 --> 執行鍵 --> 按 F6 --> 指定
Option : SS
Command : CALL SNDSRCC (&F &L &N) --> 執行鍵儲存。
即可於 PDM 中直接於選項處輸入 SS 集會出現以下畫面:
Send Source Member
From File . . . . . . . : QDDSSRC
From Library. . . . . : VENGOAL
From System . . . : SYSTEM1
Type the file name, library, and system to receive the source member.
To File . . . . . . . : QDDSSRC
To Library . . . . : VENGOAL
To System . . . . : SYSTEM2
To rename copied member, type New Name, press Enter.
Member New Name
GETDSPX GETDSPX
F3=Exit F12=Cancel
程式原始碼如下,記得要更改原始及目的主機名稱。
/*------------------------------------------------------------------*/
/* PROGRAM NAME: SNDSRCC */
/* DATE WRITTEN: 05/14/2003 */
/* FUNCTION....: THIS IS USED TO SEND A SOURCE FILE FROM A */
/* SOURCE SYSTEM TO A TARGET SYSEM */
/* */
/* NOTE........: THIS IS CALLED FROM PDM USER OPTION. */
/* EX: CALL PGM(QGPL/SNDSRC) PARM(&F &L &N) */
/* THE TARGET SOURCE FILE MUST HAVE QUSER *AUTHORITY */
/*------------------------------------------------------------------*/
PGM PARM(&FRMFIL &FRMLIB &FRMMBR)
DCLF FILE(SNDSRCD) RCDFMT(*ALL)
/*------------------------------------------------------------------*/
/* DEFINE ERROR VARIABLES */
/*------------------------------------------------------------------*/
DCL VAR(&ERRORSW) TYPE(*LGL)
DCL VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(100)
DCL VAR(&MSGF) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)
/* Variables needed to determine program name */
DCL VAR(&MSGKEY) TYPE(*CHAR) LEN(4)
DCL VAR(&SENDER) TYPE(*CHAR) LEN(80)
/*------------------------------------------------------------------*/
/* DEFINE AS400 SYSTEM NAMES VARIABLES (PUT YOUR AS400 SYSTEM NAMES HERE)*/
/*------------------------------------------------------------------*/
DCL VAR(&SYSNM1) TYPE(*CHAR) LEN(8) +
VALUE('SYSTEM1')
DCL VAR(&SYSNM2) TYPE(*CHAR) LEN(8) +
VALUE('SYSTEM2')
/*------------------------------------------------------------------*/
/* GLOBAL MESSAGE MONITOR TO TRAP ANY UNMONITORED ERRORS */
/*------------------------------------------------------------------*/
MONMSG (CPF9999 CPF0000 MCH0000) EXEC(GOTO ERROR)
/*------------------------------------------------------------------*/
/* SET DEFAULT VALUES */
/*------------------------------------------------------------------*/
CHGVAR VAR(&TOFIL) VALUE(&FRMFIL)
CHGVAR VAR(&TOLIB) VALUE(&FRMLIB)
CHGVAR VAR(&TOMBR) VALUE(&FRMMBR)
RTVNETA SYSNAME(&FRMSYS)
IF COND(&FRMSYS *EQ &SYSNM1) THEN(CHGVAR +
VAR(&TOSYS) VALUE(&SYSNM2))
IF COND(&FRMSYS *EQ &SYSNM2) THEN(CHGVAR +
VAR(&TOSYS) VALUE(&SYSNM1))
/*------------------------------------------------------------------*/
/* BEGIN PROGRAM LOGIC */
/*------------------------------------------------------------------*/
/* Determine the name of the program */
SNDPGMMSG MSG('Dummy message') TOPGMQ(*SAME) +
MSGTYPE(*INFO) KEYVAR(&MSGKEY)
RCVMSG PGMQ(*SAME) MSGTYPE(*INFO) MSGKEY(&MSGKEY) +
RMV(*YES) SENDER(&SENDER)
CHGVAR VAR(&PGMQ) VALUE(%SST(&SENDER 27 10))
/* CHGVAR VAR(&PGMQ) VALUE('SNDSRCC') */
RMVMSG PGMQ(*SAME (&PGMQ)) CLEAR(*ALL)
LOOP: SNDF RCDFMT(MSGCTL)
SNDRCVF RCDFMT(SNDFMT)
RMVMSG PGMQ(*SAME (&PGMQ)) CLEAR(*ALL)
IF COND((&IN03 *EQ '1') *OR (&IN12 *EQ '1')) +
THEN(GOTO CMDLBL(ENDPGM))
/*------------------------------------------------------------------*/
/* CREATE DDMF TO REMOTE SYSTEM */
/*------------------------------------------------------------------*/
CRTDDMF FILE(QTEMP/DDMF) RMTFILE(&TOLIB/&TOFIL) +
RMTLOCNAME(&TOSYS *IP)
/*------------------------------------------------------------------*/
/* COPY SOURCE MEMBER TO DDMF */
/*------------------------------------------------------------------*/
CPYF FROMFILE(&FRMLIB/&FRMFIL) TOFILE(QTEMP/DDMF) +
FROMMBR(&FRMMBR) TOMBR(&TOMBR) +
MBROPT(*REPLACE) FMTOPT(*NOCHK)
/*------------------------------------------------------------------*/
/* DELETE THE TEMPORARY DDMFILE */
/*------------------------------------------------------------------*/
DLTF FILE(QTEMP/DDMF)
GOTO CMDLBL(ENDPGM)
/*-------------------------------------------------------------------*/
/* GLOBAL ERROR HANDLING ROUTINE */
/*-------------------------------------------------------------------*/
ERROR:
STDERR1:
IF COND(&ERRORSW) THEN(SNDPGMMSG MSGID(CPF9999) +
MSGF(QCPFMSG) MSGTYPE(*ESCAPE))
CHGVAR VAR(&ERRORSW) VALUE('1')
STDERR2: RCVMSG MSGTYPE(*DIAG) MSGDTA(&MSGDTA) MSGID(&MSGID) +
MSGF(&MSGF) MSGFLIB(&MSGFLIB)
IF COND(&MSGID *EQ ' ') THEN(GOTO +
CMDLBL(STDERR3))
SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +
MSGDTA(&MSGDTA) MSGTYPE(*DIAG)
GOTO CMDLBL(LOOP)
STDERR3: RCVMSG MSGTYPE(*EXCP) MSGDTA(&MSGDTA) MSGID(&MSGID) +
MSGF(&MSGF) MSGFLIB(&MSGFLIB)
SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +
MSGDTA(&MSGDTA) MSGTYPE(*ESCAPE)
GOTO CMDLBL(LOOP)
/*-------------------------------------------------------------------*/
/* END PROGRAM */
/*-------------------------------------------------------------------*/
ENDPGM: RETURN
ENDPGM
2003-03-25 如何讓系統操作人員將使用者設定為可以進入系統?(Command EBLUSRPRF Enabled User Profile)
如何讓系統操作人員將使用者設定為可以進入系統?(Command EBLUSRPRF Enabled User Profile)
當使用者的 SignOn 錯誤次數超過系統值 QMAXSIGN 的設定值時,若另一系統值
QMAXSGNACN設為 2 或 3 時,此時系統會將使用者狀態設為失效(disabled)。所已有需要讓系統操
作人員能將該失效使用者重新設定為有效,該使用者才可以進入系統。
但在開發此工具時,需要注意不得讓系統操作人員將具有 *ALLOBJ, *SECADM, *SERVICE
高級權限的人員,執行啟用(enabled)使用者的動作。
此程式需以 QSECOFR 使用者產生,並指定繼承程式擁有者的權限,系統操作人員執行此
程式時,才能間接取得 QSECOFR 的權限,更改使用者狀態,同時亦排除更改具有高級權
限的使用者。
這裡也提供 Command EBLUSRPRF 使系統操作人員便於使用。
File : QCLSRC
Member: EBLUSRPRF
Type : CLP
Usage : 此程式需以 QSECOFR 使用者產生
CRTCLPGM EBLUSRPRF USRPRF(*OWNER)
/* Program : EBLUSRPRF */
/* Version : 1.00 */
/* System : iSeries */
/* */
/* Compile the program with user QSECOFR */
/* and adopt authority : */
/* CHGPGM PGM(EBLUSRPRF) USRPRF(*OWNER) */
RSETUSRPRF: PGM PARM(&USRPRF &PASSWORD &PWDEXP &STATUS)
DCL VAR(&USRPRF) TYPE(*CHAR) LEN(10)
DCL VAR(&PASSWORD) TYPE(*CHAR) LEN(10)
DCL VAR(&PWDEXP) TYPE(*CHAR) LEN(10)
DCL VAR(&STATUS) TYPE(*CHAR) LEN(10)
DCL VAR(&CURUSER) TYPE(*CHAR) LEN(10)
DCL VAR(&GRPPRF) TYPE(*CHAR) LEN(10)
DCL VAR(&SPCAUT) TYPE(*CHAR) LEN(100)
DCL VAR(&ALLOBJ) TYPE(*LGL)
/* Parameters for QCLSCAN */
DCL VAR(&STRINGLEN) TYPE(*DEC) LEN(3 0) VALUE(100)
DCL VAR(&STRPOS) TYPE(*DEC) LEN(3 0) VALUE(1)
DCL VAR(&PATTERN) TYPE(*CHAR) LEN(10)
DCL VAR(&PATTERNLEN) TYPE(*DEC) LEN(3 0) VALUE(10)
DCL VAR(&TRANSLATE) TYPE(*CHAR) LEN(1) VALUE('1')
DCL VAR(&TRIM) TYPE(*CHAR) LEN(1) VALUE('1')
DCL VAR(&WILD) TYPE(*CHAR) LEN(1) VALUE(' ')
DCL VAR(&RESULT) TYPE(*DEC) LEN(3 0)
/* Check userprofile existence */
CHKOBJ OBJ(QSYS/&USRPRF) OBJTYPE(*USRPRF)
MONMSG MSGID(CPF0000) EXEC(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('***** +
Error ****** invalid userprofile') +
TOPGMQ(*PRV) MSGTYPE(*ESCAPE)
ENDDO
/* new password same as userprofile */
IF COND(&PASSWORD *EQ *USRPRF) THEN(CHGVAR +
VAR(&PASSWORD) VALUE(&USRPRF))
/* retrieve current user */
RTVJOBA USER(&CURUSER)
/* Retrieve userprofile attributes */
RTVUSRPRF USRPRF(&USRPRF) SPCAUT(&SPCAUT) GRPPRF(&GRPPRF)
/* Check if the userprofile to be changed has */
/* *ALLOBJ authority. */
CHGVAR VAR(&PATTERN) VALUE('*ALLOBJ')
CALL PGM(QCLSCAN) PARM(&SPCAUT &STRINGLEN &STRPOS +
&PATTERN &PATTERNLEN &TRANSLATE &TRIM +
&WILD &RESULT)
/* String *ALLOBJ was found */
IF COND(&RESULT *NE 0) THEN(CHGVAR VAR(&ALLOBJ) +
VALUE('1'))
/* Do not allow to let userprofile QSECOFR, QSRV or */
/* any userprofile with *ALLOBJ authority or group */
/* profile QSECOFR to be changed. */
/* */
IF COND(&USRPRF = QSECOFR *OR &USRPRF = QSRV +
*OR &ALLOBJ *OR &GRPPRF *EQ QSECOFR) THEN(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('*** +
Error *** not authorised to change this +
user profile') TOPGMQ(*PRV) MSGTYPE(*ESCAPE)
ENDDO
/* Before resetting the userprofile, let the current */
/* user authenticate by typing his own password. */
/* This prevents changing a userprofile on a terminal */
/* where the normal user went for dinner. */
?CHKPWD
MONMSG MSGID(CPF0000) EXEC(RETURN)
/* Change userprofile */
CHGUSRPRF USRPRF(&USRPRF) PASSWORD(&PASSWORD) +
PWDEXP(&PWDEXP) STATUS(&STATUS)
MONMSG MSGID(CPF0000) EXEC(DO)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA('*** +
Error occurred *** see joblog') +
TOPGMQ(*PRV) MSGTYPE(*ESCAPE)
ENDDO
/* Log the changes into the History log */
SNDPGMMSG MSG('Userprofile ' *CAT &USRPRF *TCAT ' +
reset by user ' *CAT &CURUSER) TOMSGQ(QHST)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) +
MSGDTA('Userprofile ' *CAT &USRPRF *BCAT +
'reset') TOPGMQ(*PRV) MSGTYPE(*COMP)
END: ENDPGM
File : QCMDSRC
Member: RSETUSRPRF
Type : CMD
Usage : CRTCMD CMD(your-lib/EBLUSRPRF) PGM(your-lib/EBLUSRPRF)
/* Command : EBLUSRPRF */
/* Version : 1.00 */
/* System : iSeries */
/* Description : Enable userprofile and password */
RSETUSRPRF: CMD PROMPT('Enable userprofile and password')
PARM KWD(USRPRF) TYPE(*NAME) LEN(10) MIN(1) +
PROMPT('User profile')
PARM KWD(PASSWORD) TYPE(*CHAR) LEN(10) +
DFT(*USRPRF) SPCVAL((*USRPRF) (*SAME)) +
DSPINPUT(*PROMPT) PROMPT('User password')
PARM KWD(PWDEXP) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*YES) VALUES(*SAME *NO *YES) +
PROMPT('Set password to expired')
PARM KWD(STATUS) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*ENABLED) VALUES(*ENABLED *DISABLED +
*SAME) PROMPT('Status')
2003-03-12 如何於 CL 中轉換字串中每個英文單字的第一個字為大寫?
如何於 CL 中轉換字串中每個英文單字的第一個字為大寫?
File : QCLSRC
Member: CVTCASEC
Type : CLP
Usage : CRTCLPGM CVTCASEC
CALL CVTCASEC 'AS/400 IS VERY GOOD.'
pgm (&CvtText) /* Convert this text */
/*--------------------------------------------------------*/
/* declaration */
/*--------------------------------------------------------*/
dcl &CvtText *char 80
dcl &ReqUpper *char 22
dcl &ReqLower *char 22
dcl &Pos *dec 3 1
dcl &Posl *dec 3 0
dcl &Len *dec 3 0
dcl &upper *lgl
dcl &CCSIDReq *char 4 x'00000001'
dcl &CCSIDInp *char 4 x'00000000'
dcl &Uppercase *char 4 x'00000000'
dcl &Lowercase *char 4 x'00000001'
dcl &Reserved *char 10 x'00000000000000000000'
/*----------------------------------------------*/
/* QLGCNVCS - Convert Case QlgConvertCase */
/*----------------------------------------------*/
dcl &Input *char 80
dcl &Output *char 80
dcl &DataLen *char 4 x'00000050'
dcl &ErrCde *char 4 x'00000000'
/*--------------------------------------------------------*/
/* Setup Request Control Block */
/*--------------------------------------------------------*/
chgvar &ReqUpper (&CCSIDReq || +
&CCSIDInp || +
&Uppercase || +
&Reserved)
chgvar &ReqLower (&CCSIDReq || +
&CCSIDInp || +
&Lowercase || +
&Reserved)
chgvar &upper '1'
/*--------------------------------------------------------*/
/* Convert Upper (First letter), then lower case */
/*--------------------------------------------------------*/
loop:
if (&Pos *ge 80) goto endloop
/*----------------------------------------------*/
/* Convert to Lower */
/*----------------------------------------------*/
if (%sst(&CvtText &Pos 1) = ' ') do
if (*Not &Upper) do
chgvar &output ' '
chgvar %bin(&Datalen) &len
Call Pgm(QLGCNVCS) +
parm(&Reqlower +
&input +
&output +
&Datalen +
&ErrCde )
chgvar %sst(&CvtText &Posl &len) &Output
enddo
chgvar &upper '1'
chgvar &Pos (&Pos + 1)
enddo
/*----------------------------------------------*/
/* Convert to Upper */
/*----------------------------------------------*/
if (%sst(&CvtText &Pos 1) *ne ' ') do
if &upper do
chgvar &input %sst(&CvtText &Pos 1)
chgvar &output ' '
chgvar %bin(&Datalen) 1
Call Pgm(QLGCNVCS) +
parm(&ReqUpper +
&input +
&output +
&Datalen +
&ErrCde )
chgvar %sst(&CvtText &Pos 1) %sst(&Output 1 1)
chgvar &Pos (&Pos + 1)
chgvar &Posl &Pos
chgvar &upper '0'
chgvar &len 0
enddo
else do
chgvar &len (&len + 1)
chgvar %sst(&input &len 1) %sst(&CvtText &Pos 1)
chgvar &Pos (&Pos + 1)
enddo
enddo
goto loop
endloop:
SndPgmMsg Msg(&Cvttext) Msgtype(*Comp)
EndPgm
2003-02-19 如何於 CLP 中傳送著色的訊息?(Send colored message in CLP)
如何於 CLP 中傳送著色的訊息?(Send colored message in CLP)
File : QCLSRC
Member: SNDCOLMSGC
Type : CLP
Usage : CRTCLPGM SNDCOLMSGC
OS Version: All
/* TO COMPILE : */
/* */
/* CRTCLPGM PGM(XXX/SNDCOLMSG) SRCFILE(XXX/QCLSRC) */
SNDCOLMSG: PGM PARM(&MSG &COLOR &MSGTYPE)
DCL VAR(&MSG) TYPE(*CHAR) LEN(80)
DCL VAR(&COLOR) TYPE(*CHAR) LEN(1)
DCL VAR(&MSGTYPE) TYPE(*CHAR) LEN(10)
DCL VAR(&LASTBYTE) TYPE(*CHAR) LEN(1) VALUE(X'20')
DCL VAR(&TEXT) TYPE(*CHAR) LEN(82)
CHGVAR VAR(&TEXT) VALUE(&COLOR *CAT &MSG *TCAT +
&LASTBYTE)
SNDPGMMSG MSG(&TEXT) TOPGMQ(*EXT) MSGTYPE(&MSGTYPE)
SNDPGMMSG MSG(&TEXT) MSGTYPE(&MSGTYPE)
END: ENDPGM
此程式中有二個 SNDPGMMSG 指令,你可以選取一種顯示方式或二者。
二者顯示方式稍有不同,可以自行比較一下。
File : QCMDSRC
Member: SNDCOLMSG
Type : CMD
Usage : CRTCMD CMD(SNDCOLMSG) PGM(SNDCOLMSGC)
OS Version: All
/* Description : Send a colored message */
/* */
/* To compile : */
/* */
/* CRTCMD CMD(XXX/SNDCOLMSG) PGM(XXX/SNDCOLMSG) + */
/* SRCFILE(XXX/QCMDSRC) */
/* */
SNDCOLMSG: CMD PROMPT('Send colored message')
PARM KWD(MSG) TYPE(*CHAR) LEN(80) PROMPT('Message')
PARM KWD(COLOR) TYPE(*CHAR) LEN(1) RSTD(*YES) +
DFT(*GREEN) SPCVAL( +
(*GREEN X'20') +
(*GREEN_REVERSE X'21') +
(*WHITE X'22') +
(*WHITE_REVERSE X'23') +
(*GREEN_UNDERSCORE X'24') +
(*GREEN_UNDERSCORE_REVERSE X'25') +
(*WHITE_UNDERSCORE X'26') +
(*RED X'28') +
(*RED_REVERSE X'29') +
(*RED_BLINK X'2A') +
(*RED_REVERSE_BLINK X'2B') +
(*RED_UNDERSCORE X'2C') +
(*RED_UNDERSCORE_REVERSE X'2D') +
(*RED_UNDERSCORE_BLINK X'2E') +
(*TURQUOISE X'30') +
(*TURQUOISE_REVERSE X'31') +
(*YELLOW X'32') +
(*YELLOW_REVERSE X'33') +
(*TURQUOISE_UNDERSCORE X'34') +
(*TURQUOISE_UNDERSCORE_REVERSE X'35') +
(*YELLOW_UNDERSCORE X'36') +
(*PINK X'38') +
(*PINK_REVERSE X'39') +
(*BLUE X'3A') +
(*BLUE_REVERSE X'3B') +
(*PINK_UNDERSCORE X'3C') +
(*PINK_UNDERSCORE_REVERSE X'3D') +
(*BLUE_UNDERSCORE X'3E') +
) PROMPT('Color')
PARM KWD(MSGTYPE) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*INFO) VALUES(*INFO *COMP) +
PROMPT('Message type')
執行範例:
SNDCOLMSG MSG('Hello World') COLOR(*PINK)
SNDCOLMSG MSG('Error') COLOR(*RED_REVERSE_BLINK)
訂閱:
文章 (Atom)