Get attributes for an IFS object
|
Q: Is there a way I can get the attributes (date/time created/modified, file size) for
an IFS object in a CL or RPG/IV program? I have a batch file running on an NT server that
extracts some data from another server (Novell) to a directory on the AS/400. On the
AS/400 side, I want to ensure I have a file created "today" before I try to process it.
A: Yes, you can use the stat() API from the UNIX-Type APIs manual to get this
information. The time returned is in GMT, I believe. You may have to adjust it for your
timezone.
D**********************************************************************
D* File Information Structure (stat)
D*
D* struct stat {
D* mode_t st_mode; /* File mode */
D* ino_t st_ino; /* File serial number */
D* nlink_t st_nlink; /* Number of links */
D* uid_t st_uid; /* User ID of the owner of file */
D* gid_t st_gid; /* Group ID of the group of file */
D* off_t st_size; /* For regular files, the file
D* * size in bytes */
D* time_t st_atime; /* Time of last access */
D* time_t st_mtime; /* Time of last data modification */
D* time_t st_ctime; /* Time of last file status change */
D* dev_t st_dev; /* ID of device containing file */
D* size_t st_blksize; /* Size of a block of the file */
D* unsigned long st_allocsize; /* Allocation size of the file */
D* qp0l_objtype_t st_objtype; /* AS/400 object type */
D* unsigned short st_codepage; /* Object data codepage */
D* char st_reserved1[66]; /* Reserved */
D* };
D*
D statds DS
D st_mode 10U 0
D st_ino 10U 0
D st_nlink 5U 0
D st_pad 2A
D st_uid 10U 0
D st_gid 10U 0
D st_size 10I 0
D st_atime 10I 0
D st_mtime 10I 0
D st_ctime 10I 0
D st_dev 10U 0
D st_blksize 10U 0
D st_alctize 10U 0
D st_objtype 12A
D st_codepag 5U 0
D st_resv11 67A
D*--------------------------------------------------------------------
D* Get File Information
D*
D* int stat(const char *path, struct stat *buf)
D*--------------------------------------------------------------------
D stat PR 10I 0 ExtProc('stat')
D path * value
D buf * value
D Path S 640A
D Msg S 52A
D ModTime S Z INZ(z'1970-01-01-00.00.00.00000')
c eval Path = '/QOpenSys/usr/myfile.txt'+x'00'
c if stat(%addr(Path): %addr(statds)) <> 0
c eval Msg = 'stat() failed!'
c dsply Msg
c eval *inlr = *on
c return
c endif
c adddur st_mtime:*s ModTime
c 'Changed' dsply ModTime
c eval *inlr = *on
Thanks to Scott Klement
|
|
Back
Generate a screen print like "Print-Key"- Function
|
Here's a DSM example:
**-- Header specifications: --------------------------------**
H BndDir( 'QC2LE' : 'QSNAPI' ) Option( *SrcStmt )
**-- Global variables: -------------------------------------**
D InpBufHdl s 10i 0
D InpDtaPtr s *
**-- Parameters: -------------------------------------------**
D Parm Ds
D Row 10i 0
D Col 10i 0
D NbrBytRtn 10i 0
D Screen 3564a
**-- Prototype for DSM API's: ------------------------------**
D GetCsrAdr Pr 10i 0 ExtProc( 'QsnGetCsrAdr' )
D Row 10i 0
D Col 10i 0
D LlvEnvHdl 10i 0 Const Options( *Omit )
D ApiError 1024a Options( *Omit: *VarSize )
**
D CrtInpBuf Pr 10i 0 ExtProc( 'QsnCrtInpBuf' )
D InpBufSiz 10i 0 Const
D BufIncSiz 10i 0 Const Options( *Omit )
D BufMaxSiz 10i 0 Const Options( *Omit )
D InpBufHdl 10i 0 Options( *Omit )
D ApiError 1024a Options( *Omit: *VarSize )
**
D ReadScr Pr 10i 0 ExtProc( 'QsnReadScr' )
D NbrBytRead 10i 0 Options( *Omit )
D InpBufHdl 10i 0 Const Options( *Omit )
D CmdBufHdl 10i 0 Const Options( *Omit )
D LlvEnvHdl 10i 0 Options( *Omit )
D ApiError 1024a Options( *Omit: *VarSize )
**
D RtvDta Pr * ExtProc( 'QsnRtvDta' )
D InpBufHdl 10i 0 Const
D InpDtaPtr * Options( *Omit )
D ApiError 1024a Options( *Omit: *VarSize )
**
D Beep Pr 10i 0 ExtProc( 'QsnBeep' )
D CmdBufHdl 10i 0 Const Options( *Omit )
D LlvEnvHdl 10i 0 Const Options( *Omit )
D ApiError 1024a Options( *Omit: *VarSize )
**
D DltBuf Pr 10I 0 ExtProc( 'QsnDltBuf' )
D BufferHdl 10I 0 Const
D ApiError 1024a Options( *Omit: *VarSize )
**
D MemCpy Pr * ExtProc( 'memcpy' )
D pOutMem * Value
D pInpMem * Value
D InpMemSiz 10u 0 Value
**
**--Mainline: ----------------------------------------------**
**
C Eval InpBufHdl = CrtInpBuf( 27 * 132
C : *Omit
C : *Omit
C : *Omit
C : *Omit )
**
C CallP GetCsrAdr( Row
C : Col
C : *Omit
C : *Omit )
**
C Eval NbrBytRtn = ReadScr( *Omit
C : InpBufHdl
C : *Omit
C : *Omit
C : *Omit )
**
C Eval InpDtaPtr = RtvDta( InpBufHdl
C : *Omit
C : *Omit )
**
C CallP MemCpy( %Addr( Screen )
C : InpDtaPtr
C : NbrBytRtn )
**
C CallP Beep( *Omit
C : *Omit
C : *Omit )
**
C CallP DltBuf( InpBufHdl: *Omit )
**
C Return
Thanks to Carsten Flensburg
|
|
Back
Q: Is there a way to bind in the regex functions in rpg?
Similar to the way you would use the other c functions?
A: Okay... I converted the example from the "ILE C for AS/400 Runtime
reference" into RPG (more or less). The difference being that I used
diagnostic messages and escape messages instead of printf-type messages.
H BNDDIR('QC2LE') DFTACTGRP(*NO)
D regex_t DS align
D re_nsub 10I 0
D re_comp *
D re_cflags 10I 0
D re_erroff 10I 0
D re_len 10I 0
D re_ucoll 10I 0 dim(2)
D re_lsub * DIM(9)
D re_esub * DIM(9)
D re_map 256A
D re_shift 5I 0
D re_dbcs 5I 0
D regmatch_t DS occurs(2) align
D rm_so 10I 0
D rm_ss 5I 0
D rm_eo 10I 0
D rm_es 5I 0
D regcomp PR 10I 0 extproc('regcomp')
D preg * value
D pattern * value
D cflags 10I 0 value
D regexec PR 10I 0 extproc('regexec')
D preg * value
D string * value
D nmatch 10U 0 value
d pmatch * value
D eflags 10I 0 value
D regerror PR 10U 0 extproc('regerror')
D errcode 10I 0 value
D preg * value
D errbuf * value
D errbuf_size 10I 0 value
D regfree PR extproc('regfree')
D preg * value
D DiagMsg PR
D peMsgTxt 256A Const
D EscapeMsg PR
D peMsgTxt 256A Const
D preg S *
D pmatch S *
D string S 50A
D len S 10I 0
D rc S 10I 0
D nmatch S 10U 0 INZ(2)
D Msg S 50A
D Buf S 256A
D pattern S 50A
c eval *inlr = *on
c* Set example values
c eval string = 'a very simple simple ' +
c 'simple string' + x'00'
c eval pattern = '\(sim[a-z]le\) \1' + x'00'
c* Initialize pointers
c 1 occur regmatch_t
c eval preg = %addr(regex_t)
c eval pmatch = %addr(regmatch_t)
C* Compile RE
c eval rc=regcomp(preg:%addr(pattern):0)
c if rc <> 0
c callp regerror(rc: preg: %addr(buf): 256)
c callp EscapeMsg('regcomp() failed with: ' +
c %str(%addr(buf)))
c endif
C* Execute RE
c eval rc = regexec(preg: %addr(string):
c nmatch: pmatch: 0)
c if rc <> 0
c callp regerror(rc: preg: %addr(buf): 256)
c callp regfree(preg)
c callp EscapeMsg('regexec() failed with: ' +
c %str(%addr(buf)))
c endif
C* Show results:
c 1 occur regmatch_t
c eval len = rm_eo - rm_so
c eval rm_so = rm_so + 1
c callp DiagMsg('With the whole expression, ' +
c 'a matched substring "' +
c %subst(string: rm_so: len) +
c '" is found at position ' +
c %trim( %editc(rm_so: 'Z') ) +
c ' to ' + %trim( %editc(rm_eo: 'Z') ))
c 2 occur regmatch_t
c eval len = rm_eo - rm_so
c eval rm_so = rm_so + 1
c callp DiagMsg('With the sub-expression, ' +
c 'a matched substring "' +
c %subst(string: rm_so: len) +
c '" is found at position ' +
c %trim( %editc(rm_so: 'Z') ) +
c ' to ' + %trim( %editc(rm_eo: 'Z') ))
c callp regfree(preg)
c return
P*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P* This puts a diagnostic message into the job log
P*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P DiagMsg B
D DiagMsg PI
D peMsgTxt 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 1A
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 wkMsgLen S 10I 0
D wkTheKey S 4A
c ' ' checkr peMsgTxt wkMsgLen
c if wkMsgLen<1
c return
c endif
c callp SndPgmMsg('CPF9897': 'QCPFMSG *LIBL':
c peMsgTxt: wkMsgLen: '*DIAG':
c '*': 0: wkTheKey: dsEC)
c return
P E
P*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P* This ends the program with an escape message
P*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P EscapeMsg B
D EscapeMsg PI
D peMsgTxt 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 1A
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 wkMsgLen S 10I 0
D wkTheKey S 4A
c ' ' checkr peMsgTxt wkMsgLen
c if wkMsgLen<1
c return
c endif
c callp SndPgmMsg('CPF9898': 'QCPFMSG *LIBL':
c peMsgTxt: wkMsgLen: '*ESCAPE':
c '*PGMBDY': 1: wkTheKey: dsEC)
c return
P E
Thanks to Scott Klement
Seems to be some troubles with Scott's example for people outside the USA.
This could be a help:
Franz wrote:
I tried to use the C-function regex in RPG. For this, there is a
sourcefile in C in the "C / C++ Programmersguide" and a RPG-program at
"http://www.think400.dk/adhoc_3.htm".
With both programs, I get the message "Failed to match".
First I think, its a problem of the character set. But i can't find out.
Barbara Morris wrote:
I think you're right that it's a character set problem.
I put that source into a CCSID(37) file and it ran as expected. I
copied it into a CCSID(273) file and changed my job to 273, and compiled
it again, and it got the "Failed to match" error when it ran.
When I corrected the CCSID(273) source so that the backslash and
square-bracket characters \[] were correct, and recompiled, the program
ran fine.
Thanks to both Franz and Barbara
Tutorials for Regular Expressions:
Link I
Link II
Utility for Regular Expressions
Thanks to Buck Calabro
|
|
Back
Configuring SMTP E-Mail for SNA distribution
|
Add Host Table Entry for SMTP Gateway:
Option 10 from CFGTCP - add a host table entry for the SMTP gateway and
call it something like ‘SMTPGATE’ and then CHGSMTPA to add the SMTP gateway
as the router (MAILROUTER parm) and change firewall to 'YES'.
Change the AS/400 TCP/IP Domain:
Option 12 from CFGTCP. Make sure your Host Name is the AS/400 name (e.g.
MYAS400 or S103456) and the domain name conforms to your network standard B
e.g mycompany.com or London.yc (if you have your own intranet domain)
You may need a DNS server ? if you don't have one, use your ISP’s one.
Add a Directory Entry as Route to SMTP Gateway:
Add a new entry to the system distribution directory to define the Route to
SMTP gateway. The User ID and Address of this entry is later specified with
the SMPTPRTE parameter for the Change Distribution Attributes (CHGDSTA)
command.
The directory entry must specify the following:
The User ID and Address (USRID) can be anything, but should indicate that
this entry refers to Internet or SMTP users. The suggested entry is:
USRID(INTERNET SMTPRTE)
Users do not need to know this address, but you must specify the same value
when changing the Distribution Attributes in Configure Route to SMTP
Gateway in Distribution Attributes later.
The User entry description (USRD) again can be anything, but should
indicate that this entry refers to Internet or SMTP users. Suggestion:
USRD('User ID to route Internet addresses')
As User profile name (USER), \NONE should be specified.
The System name (SYSNAME) can be anything different to this system's name
or other system in the SNADS network (for example, you might choose:
INTERNET).
The Network User ID (NETUSRID) must be the same as the User ID and Address
(that is, specify USRID).
The Mail Service Level (MSFSRVLVL) must be \USRIDX. (that is, option 1
when using the Work with Directory Entries (WRKDIRE) command.
The Preferred address (PREFADR) must be:
Field Name = NETUSRID,
Product ID = *IBM,
Address Type = ATCONTXT.
Configure Route to SMTP Gateway in Distribution Attributes:
The user ID and address for the system distribution directory entry added
in AConfigure Route to SMTP Gateway in Distribution Attributes@ now needs
to be specified with the Change Distribution Attributes (CHGDSTA) command.
In any AS/400 command line, type CHGDSTA and press F4.
Change Distribution Attributes (CHGDSTA)
Keep recipients . . . . . . . . *BCC
Use MSF for local . . . . . . . *NO
Route to SMTP gateway:
User ID . . . . . . . . . . . INTERNET
Address . . . . . . . . . . SMTPRTE
STRTCPSVR *SMTP
Authorities: You may need to GRTOBJAUT to the mail server framework objects
in QSYS. (Try QMSF* and MSF*)
SNDDST to send a document or file to a network user, send to user INTERNET
on system SMTPRTE, using the INETADR field for the recipient –
‘someone@somewhere.com’
Thanks to 'unknown'
|
|
Back
Guide to block mail relay and spamming
|
You can block mail relay and spamming using the following instructions.
The information was copied from here:
Special instructions for controlling RELAY and CONNECTIONS
----------------------------------------------------------
If you do not choose to take advantage of this enhanced function,
nothing needs to be done. If you want to take advantage of this
enhanced function, you should do the following:
Special Instructions for RESTRICTING RELAY:
1. Create a Source Physical File QUSRSYS/QTMSADRLST
record length 92 (12 characters for line count and change
information). The file must be ccsid 500.
CRTSRCPF FILE(QUSRSYS/QTMSADRLST) CCSID(500)
2. Create a Source Physical File member ACCEPTRLY
To create a member for a file that already exists (and go into
edit):
STRSEU SRCFILE(QUSRSYS/QTMSADRLST) SRCMBR(ACCEPTRLY)
3. Add a record with the dotted decimal address of the ALLOWED user.
Only addresses in the list will be allowed to relay.
Put one address and mask per line, (a mask is optional).
An example entry would be:
1.2.3.4 255.255.0.0
In this example the mask and the address would be combined (AND)
to allow all addresses starting with '1.2' e.g. '1.2.5.6'
Another example:
7.8.9.3 255.255.255.255
This would allow only one address, 7.8.9.3. It is the same as
7.8.9.3
Special Instructions for RESTRICTING CONNECTIONS:
1. Create a Source Physical File QUSRSYS/QTMSADRLST record
length 92 (12 characters for line count and change information).
The file must be ccsid 500.
CRTSRCPF FILE(QUSRSYS/QTMSADRLST) CCSID(500)
2. Create a Source Physical File member REJECTCNN
To create a member for a file that already exists (and go into
edit):
STRSEU SRCFILE(QUSRSYS/QTMSADRLST) SRCMBR(REJECTCNN)
3. Add a record with the dotted decimal address of the REJECTED user.
This blocks relay and mail delivery from this address.
Put one address and mask per line (a mask is optional).
An example entry would be:
1.2.3.4 255.255.0.0
In this example the mask and the address would be combined (AND)
to reject all address starting with '1.2' e.g. '1.2.5.6'
Another example:
7.8.9.3 255.255.255.255
This would reject only one address, 7.8.9.3. It is the same as
7.8.9.3
Instructions for activating relay and connection lists
1. End the smtp server
ENDTCPSVR SERVER(*SMTP)
2. If data area for blocking all relays exists, delete it.
To see if the data area exists:
DSPDTAARA DTAARA(QUSRSYS/QTMSNORLY)
To delete the data area:
DLTDTAARA DTAARA(QUSRSYS/QTMSNORLY)
3. Start the smtp server
STRTCPSVR SERVER(*SMTP)
Special notes:
1. If the data area for blocking relays is used (QUSRSYS/QTMSNORLY),
ALL relays will be blocked. If the data area is not there, but
QUSRSYS/QTMSADRLST.ACCEPTRLY exists and has at least one entry,
then only addresses in the list will be allowed to relay.
2. If the address is in QUSRSYS/QTMSADRLST.REJECTCNN it will not
be allowed to connect. This blocks relay and mail delivery from
this address. If QUSRSYS/QTMSADRLST.REJECTCNN does not exist
or has no valid entries, then all connections will be allowed.
3. If journaling is on, rejected addresses will be journaled.
To find out if journaling is on:
Use PF4 on command CHGSMTPA, look for parameter Journal
which would be *YES for on.
To display journal,('sues/jrnl' is your directory and file,
'dec14' is the name of the member you are creating):
DSPJRN JRN(QZMF) OUTPUT(*OUTFILE) OUTFILE(sues/jrnl) OUTMBR(dec14)
ENTDTALEN(512)
DSPPFM FILE(sues/jrnl) MBR(dec14)
Rejected connections will have the entry, starting in column 195:
"9S CONNECTION REFUSED 1.2.3.4"
(1.2.3.4 is the dotted decimal address rejected.)
Rejected relays will have the entry, starting in column 195:
"9V RELAY REFUSED 1.2.3.4"
(1.2.3.4 is the dotted decimal address rejected.)
These journal entries will have a message id of 0.
4. Relays will be rejected with the SMTP protocol response,
in the SMTP client to SMTP server conversation:
"553 Relaying blocked at this site."
5. Connections will be rejected with the SMTP protocol response,
in the SMTP client to SMTP server conversation:
"421 Service not available, access denied."
6. Only the first 10,000 entries in each table will be read.
Lines beginning with '*' will be treated as comments.
The file must be ccsid 500. Only put one address and mask per
line. If you FTP your file between systems, make sure it is
created as a source physical file on the receiving system first.
7. Error messages will appear in the QTSMTPSRVR joblog as follows:
Entries in the QUSRSYS/QTMSADRLST that are not valid:
"TCP9508" "Internet address not valid."
Note that the above message will always be followed by the
following message to indicate which file member has problems.
The entries not in error will still be used.
Any error with file QUSRSYS/QTMSADRLST:
"TCP2062" "SMTP job not able to use file QTMSADRLST."
Except for entry errors, the above message will result in the
actions that would occur if there were no file.
Error getting temporary space for lists, which will result in
actions that would occur if there were no file:
"TCP1062" "Not enough storage available."
Read errors on file QUSRSYS/QTMSADRLST, may result in a partial
file being used:
"TCP12B5" "Unable to read data from file QTMSADRLST."
8. If changes are made to QUSRSYS/QTMSADRLST, the SMTP Server
must be restarted for the changes to take effect:
ENDTCPSVR SERVER(*SMTP)
STRTCPSVR SERVER(*SMTP)
Last news:
However, a new test using a customer's domain name and the %sign is being done.
The % sign is a routing character and can be disabled. SMTP users should run the
CHGSMTPA command, and press F4 to prompt. Then, change the Percent Routing Character
parameter value to *NO if you do not use this option. This disables this option,
and you will not be labeled as an OPEN RELAY by the testing companies.
Thanks to Makins
From V5R1 on
Do the following:
chgsmtpa alwrly(*list)
addsmtple type(*accept) intnetadr('n.n.n.n') subnetmask('255.255.255.255') -
where n.n.n.n is the IP address of your AS/400
endtcpsvr *smtp
strtcpsvr *smtp
Note. If you are coming from V4 and you already used the anti-spam technique, just enter command
chgsmtpa alwrly(*list)
and restart SMTP.
File QUSRSYS/QTMSADRLST is read from SMTP, its records converted to "smtp-list-entries",
and the file is deleted. This is why, if you try to enter the above command
addsmtple type(*accept) intnetadr('n.n.n.n')
you get the message "duplicate entry".
Thanks to Giovanni Perotti
SMTP - High usage, but not running
To prevent this from happening in the first place, you'll need to restrict SMTP relaying.
Use the CHGSMTPA command to change the allow relay setting from *ALL to *LIST. Then,
create an accept entry for your AS400 using the ADDSMTPLE command. For example, if the
IP address of your system is 10.1.1.1, then run the command:
ADDSMTPLE TYPE(*ACCEPT) INTNETADR('10.1.1.1') SUBNETMASK('255.255.255.255')
This will allow your AS400 to send mail, but nobody else. Once this has been set up,
end the SMTP server and restart it.
If high activity continues, then end the SMTP server again and run the following command:
CRTDTAARA DTAARA(QUSRSYS/QTMSCLEAN) TYPE(*CHAR) LEN(1) VALUE('C') AUT(*ALL)
Then, start your SMTP server one more time. At this point, any pending messages that the
server was continuing to try and send will be cancelled.
Thanks to Rich Loeber
|
|
Back
Problems with MSF and SMTP server
|
Q:
It seems that every time MSF starts up, we get errors logged about undeliverable messages.
I suspect that these are really old messages that should just be cleared out, but I'd like
to confirm that.
Google is not my friend today, nor any of the other days that I've tried to look at this
problem. I've read over what seem to be the relevant portions of the 'AnyMail/400 Mail
Server Framework Support' book from IBM (SC41-5411-00).
The only option I've turned up in my searches is to use the QzmfRtvMailMsg API to get
information about the undeliverable messages. This is rather a complex API. Is there another
way to peek at MSF messages?
A:
I've run into this problem on occasion when a bad email address causes it
to have a problem. The solution is to clear things out completely in the
queue and restart fresh.
I have the following CL program that I use. It has one parm. If the parm
is set to C, only the most recent entry in the queue is cleared. If it is
set to X, then the entire queue is cleared. End MSF before you run this,
then restart it when this is done:
PGM PARM(&CODE)
DCL VAR(&CODE) TYPE(*CHAR) LEN(1) /* 'X' or 'C' */
IF COND((&CODE *EQ 'X') *OR (&CODE *EQ 'C')) +
THEN(DO)
ENDTCPSVR SERVER(*SMTP)
CRTDTAARA DTAARA(QUSRSYS/QTMSCLEAN) TYPE(*CHAR) LEN(1) +
VALUE(&CODE) AUT(*ALL)
DLYJOB DLY(10)
STRTCPSVR SERVER(*SMTP)
ENDDO
ENDPGM
Thanks to Rich Loeber
A:
Actually, the MSF mail messages do not live in the IFS, they are a hold over from the old Office
Vision/400 and/or Document Library Object days. But if you poke around enough you can find them.
Here's some snippets and tips which should get you headed in the right direction.
As always, backup is your friend. You can do a SAVDLO DLO(*MAIL) DEV(*SAVF) to grab a copy of
things before you start deleting them.
They were based on the IBM document below which is no longer available online, or at least I
wasn't able to find it anymore.
__________________________________________________________________
IBM Software Technical Document
__________________________________________________________________
Document Number: 15451115
Functional Area: AS/400 Mail
Subfunctional Area: OfficeVision - Mail
Sub-Subfunctional Area: General
OS/400 Release: ALL
Product: Operating System/400 - OS/400 COMM BASE (5716SS1CM)
Product Release: N/A
__________________________________________________________________
Document Title
Example (CL) - Cleanup SNADS Mail Distributions
__________________________________________________________________
=====
Start by using DSPDIRE to outfile to get a list of all users who could be sending MSF mail
=====
DSPDIRE OUTPUT(*OUTFILE) OUTFILE(&OUTLIB/&OUTFILE)
OUTMBR(*FIRST *REPLACE) DETAIL(*FULL) +
OUTFILFMT(*TYPE3) OUTDTA(*ALL)
=====
Even if you use an *ALLOBJ userid, or even QSECOFR, you may not be able to access the mail for
the users listed above. I ended up having to loop through the above file and use the Grant User
Permission (GRTUSRPMN) command to myself.
=====
DCLF FILE(QSYS/QAOSDIRX) RCDFMT(OSDIRX)
OVRDBF FILE(QAOSDIRX) TOFILE(&OUTLIB/&OUTFILE)
LOOP: RCVF RCDFMT(OSDIRX)
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
IF COND(&DXUSRP *NE ' ') THEN(+
DO)
GRTUSRPMN TOUSER(BDOLINAR) FORUSER(&DXUSRP)
ENDDO
DONE: ENDPGM
=====
And now that you have the ability to look at all the MSF mail, there are two "piles" of mail,
incoming and outgoing. Use the Query Distribution (QRYDST) command to send each of them to their
own outfile by looping through the DSPDIRE list of users. From what I remember, the *IN and *OUT
files have different layouts and use different parameters on the QRYDST command.
=====
LOOP: RCVF RCDFMT(OSDIRX)
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
IF COND(&DXUSRP *NE ' ') THEN(DO)
QRYDST OPTION(*IN) USRID(&DXDEN &DXDGN) +
OUTFILE(&OUTLIB/QRYDSTIN) OUTMBR(*FIRST +
*ADD) STATUS(*ALL)
MONMSG MSGID(CPF0000)
ENDDO
GOTO CMDLBL(LOOP)
DONE: ENDPGM
=====
LOOP: RCVF RCDFMT(OSDIRX)
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
IF COND(&DXUSRP *NE ' ') THEN(+
DO)
QRYDST OPTION(*OUT) USRID(&DXDEN &DXDGN) +
OUTFILE(&OUTLIB/QRYDSTOUT) OUTMBR(*FIRST +
*ADD)
MONMSG MSGID(CPF0000)
ENDDO
GOTO LOOP
DONE: ENDPGM
=====
The "Distribution ID" fields, LINDID and OUTDID, along with the Recipient/Sender Identifier,
LINRUI and OUTSUI, and Recipient/Sender Address LINRUA and OUTSUA fields, is the information
needed from the two QRYDST files to actually identify an MSF mail message so you can send them
to their own output files.
While in theory you should be able to send both incoming and outgoing distributions to an output
file, I was only able to do it for the incoming. All the outgoing ones were *ERR type messages,
so I just deleted them to get them out of the system.
=====
DCLF FILE(QSYS/QAOSILIN) RCDFMT(OSLIN)
/* GLOBAL MONMSG */
MONMSG MSGID(CPF9098 CPF900C)
OVRDBF FILE(QAOSILIN) TOFILE(BCDLIBOV4/QRYDSTIN)
LOOP: RCVF RCDFMT(OSLIN)
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
RCVDST DSTID(&LINDID) USRID(&LINRUI &LINRUA) +
OUTFILE(&OUTLIB/RCVDSTIN) ACKRCV(*YES) +
DSTIDEXN(*NONE) KEEP(*YES)
GOTO CMDLBL(LOOP)
DONE: ENDPGM
=====
=====
/* WARNING - THIS CODE DELETES THE OUTGOING DISTRIBUTIONS WITHOUT SAVING THEM */
DCLF FILE(QSYS/QAOSILOT) RCDFMT(OSLOUT)
OVRDBF FILE(QAOSILOT) TOFILE(BCDLIBOV4/QRYDSTOUT)
LOOP: RCVF RCDFMT(OSLOUT)
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(DONE))
DLTDST DSTID(&OUTDID) OPTION(*OUT) USRID(&OUTSUI +
&OUTSUA) DSTIDEXN(&OUTDEX)
MONMSG MSGID(CPD9022 CPF900A) EXEC(DO)
/* CPD9022 DISTRIBUTION ISSPRD-BSYPGMR-0039-00 CANNOT BE F
DLTDST DSTID(&OUTDID) OPTION(*ERR) USRID(&OUTSUI +
&OUTSUA) DSTIDEXN(&OUTDEX)
MONMSG MSGID(CPF900A)
ENDDO
=====
Thanks to Brian Dolinar
|
|
Back
System Reference Codes at IPL time
|
IPL SRC Format Description:
As the system performs an IPL, SRCs appear on the control panel. The SRCs
indicate the status of the IPL and are often useful in problem analysis.
The following list provides information on the IPL process and shows some
SRCs (in numeric order) that can appear during an IPL.
IPL SRC Function Performed
C1xx 1xxx Service Processor ROS IPL in progress
C1xx 1006 Service processor ROS loading RAM from MFIOP directed device
C1xx 1007 Service Processor ROS retrying attempt to load RAM from MFIOP directed device
C1xx 1008 Service Processor ROS attempting to load RAM from non-MFIOP directed device
C1xx 1009 Service Processor ROS retrying attempt to load RAM from non-MFIOP directed
device
C1xx 1016 Service Processor ROS attempting to load RAM from MFIOP default device
C1xx 1018 Service Processor ROS attempting to load RAM from non-MFIOP default device
C1xx 1019 Service Processor ROS retrying attempt to load RAM from non-MFIOP default device
C1xx 100C Service processor ROS IPL complete, branch to RAM Loader
C1xx 1030 Loading Service Processor system LIC from MFIOP device
C1xx 1050 Loading Service Processor system LIC from non-MFIOP device
C1xx 2001 Service Processor is setting up to test and load system processor
C1xx 2002 Service processor is testing system processor and main storage
C1xx 2003 Service processor is loading system processor
C100 2034 LIC (system) has been initialized; control has passed to system processor
C1xx 2050 Service Processor is waiting for Load Source device
C1xx 2060 Service Processor started a read command from Load Source
C1xx 2090 Service Processor completed a read command from load source
C1xx 80xx Service Processor/Control Panel communication in progress
C1xx 805x Service Processor is loading Control Panel LIC
C1xx B1xx Basic assurance test completed on MFIOP
C100 D009 LIC (system) running initialization
C200 1xxx Secondary Partition Early IPL Initialization Phase
C200 1100 Adding partition resources to the secondary configuration
C200 11FF Partition resources added successfully
C200 2xxx Secondary Partition SPCN Tower Power ON Phase
C200 1200 Checking if IPL is allowed
C200 12FF Partition IPL is allowed to proceed
C200 1300 Initializing ISL roadmap
C200 13FF ISL roadmap initialized successfully
C200 1400 Initializing SP Communication Area #1
C200 1410 Initializing IPL parms
C200 14FF IPL parms initialized successfully
C200 3xxx Secondary Partition Bus Unit ISL Phase
C200 3100 Validating ISL command parameters
C200 3111 Waiting for Bus object to become operational
C200 3112 Waiting for bus unit to become disabled
C200 3150 Sending ISL command to bus unit
C200 31FF Waiting for ISL command completion
C200 32FF ISL Command complete successfully
C200 4xxx Secondary Partition Load Source Device Connection Phase
C200 4100 Waiting for load source device to enlist
C200 4200 Load source device has enlisted
C200 4300 Preparing connection to load source device
C200 43FF Load source device is connected
C200 5xxx Secondary Partition Main Storage Dump Phase
C200 5100 Preparing to initiate MSD phase
C200 5110 Loading SID 82 from load source device
C200 5115 MSD Phase I
C200 5120 Writing processor registers into SID 82
C200 5125 MSD Phase II
C200 5130 Writing mainstore pages to the load source device
C200 5135 MSD Phase III
C200 5140 Storing (final) SID 82 back to the load source device
C200 5150 Allocating the hardware page table
C200 51FF MSD processing complete
C200 6xxx Secondary Partition Load LIC from Load Source Phase
C200 6000 Locating First LID information on the loadsource
C200 6010 Locating Next LID information on the loadsource
C200 6020 Verifying LID information
C200 6030 Priming LP Configuration LID
C200 6040 Preparing to initiate LID load from loadsource
C200 6050 LP Configuration LID primed successfully
C200 6060 Waiting for LID load to complete
C200 6100 LID load completed successfully
C200 7xxx Secondary Partition Load Source Device Disconnection Phase
C200 7100 Disconnecting from load source device
C200 7110 Preparing to remove the load source IOP from the primary partition
C200 7120 Load source IOP has been successfully removed from the primary partition
C200 71FF Load source is successfully disconnected
C200 8xxx Secondary Partition Start Processors Phase
C200 8100 Initializing SP Communication Area #2
C200 8104 Loading data structures into mainstore
C200 8110 Initializing event paths
C200 8120 Starting processors
C200 81FF Processors started successfully, now waiting to receive the continue
acknowledgment from SLIC
C200 8200 Continue acknowledgment received from SLIC
C200 82FF VSP IPL complete successfully
C3xx xxxx System Processor or Main Storage Diagnostic in progress
C5xx xxxx LIC system hardware initialization
C500 C92B Waiting for console device - error condition only if console not found
C6xx 1800 LIC SPCN setup
C600 3900 SP transfer control of Bus 1 (BCU Switch) to LIC is Complete and LIC Machine
Facilities component is initialized
C600 3910 LIC has initiated PCI Bus Reset to all Bus 1 devices except the SP
C600 3911 LIC has initiated self-test of all Bus 1 devices except the SP
C600 3912 LIC is initiating IPL of the Load Source IOP
C600 3913 LIC is initializing the Load Source IOP messaging functions
C600 3914 LIC has detected a Load Source IOP problem and is resetting the IOP, or the IOP
has requested a reset after an internal Flash memory LIC update
C600 3915 LIC has initiated the Load Source IOP self-load
C600 3916 During self-load, the Load Source IOP signaled LIC that it is initiating an internal
Flash Memory update or other critical function
C600 3917 The Load Source IOP has completed IPL of its operational load, LIC is waiting for
the IOP to report its attached IO resources
C600 4001 Static paging
C600 4002 Start limited paging, call LID manager
C600 4003 Initialize IPL/Termination (IT) data area / set up node address communication area
(NACA) pointer
C600 4004 Check and update MSD SID
C600 4005 Initialize event management is running
C600 4006 IPL all buses
C600 4007 Start error log ID
C600 4008 Initialize I/O service
C600 4009 Initialize I/O machine
C600 4010 Initialize IDE (interactive device exerciser)
C600 4011 Initialize remote services
C600 4012 Initialize RMAC component data values
C600 4013 Initialize context management
C600 4014 Initialize RM (component) seize lock
C600 4015 Initialize MISR
C600 4016 Set time of day
C600 4017 Initialize RM (component) process management
C600 4018 Initialize error log
C600 4019 Restart the service processor
C600 4020 Initialize machine services
C600 4021 Initialize performance data collector
C600 4022 Initialize event management
C600 4023 Create MI boundary manager tasks
C600 4024 Disable CPM
C600 4025 Initializes battery test
C600 4026 Hardware card checkout
C600 4027 Start integrated device exerciser (Type C IPL only)
C600 4028 Start DST
C600 4029 Make IPL task not critical
C600 4030 Free static storage
C600 4031 Destroy IPL task
C600 4032 Initialize Integrated File System descriptor management
C600 4033 Initialize LPAR Virtual I/O
C600 4050 Storage management recovery is running
C600 4051 Start LOG is running
C600 4052 Trace table initialization is running
C600 4053 Context rebuild is running
C600 4054 Start product activity log and Advanced Peer-to-Peer Networking (APPN) is running
C600 4055 Authority recovery is running
C600 4056 Journal recovery is running
C600 4057 Database recovery is running
C600 4058 Journal synchronization is running
C600 4059 Commit recovery is running
C600 4060 Database initialization is running
C600 4061 Journal IPL clean up is running
C600 4062 Commit initialization is running
C600 4064 System Object Model ? (SOM) recovery is running
C600 4065 Start operating system is running
C600 4100 Searching for Load Source Candidate (D-mode only)
C600 4101 Opening media-file to install LIC service displays with proper National Language
Version
C600 4102 Loading and linking from media-file to install LIC service displays with proper
National Language Version
C600 4201 Storage management recovery
C600 4204 Synchronization of mirrored MSD
C6xx 4205 Synchronization of mirrored data (where xx is percent complete).
C600 4240 Reclaim main storage
C600 4250 Storage management subset directory recovery
C600 4255 Defragmentation utility
C600 4260 Storage management directory recovery
C600 4272 ASP overflow recovery
C600 4300 Static paging is available for the link loader
C600 4301 Applying temporary PTFs. If the IPL stops at this point, you might need to install
the Licensed Internal Code again.
C600 4302 Applying modules. If the IPL stops at this point, you might need to install the
Licensed Internal Code might again.
C600 4303 Temporarily applied PTFs have reached the static paging phase
C600 432A Resolving references to run Mode A; you can safely stop the system while it is doing
this work.
C600 432B Resolving references to run Mode B. You may safely stop the system while it is doing
this work.
C600 4330 Full paging is available; workstation HRI processing
C600 4331 Freeing unused nucleus pages
C600 4332 Permanently applying PTFs. If the IPL stops at this point, you may need to install
the Licensed Internal Code again.
Main Storage Dump IPL SRCs:
C6xx 4400 Unattended DASD checker started
C6xx 4401 Attended DASD checker started
C600 4402 Main storage dump manager and storage management recovery started
C600 4403 Storage management recovery ended
C6xx 4404 LIC log started (where xx is dump copy percent completed).
C600 4405 Dump auto copy completed. Shutdown or programmed IPL has started.
C600 4406 Shutdown or programmed IPL (MSD related) has started.
Continuously Powered Main Storage (CPM) IPL SRCs:
C6xx 4410 Unattended DASD checker started
C6xx 4411 Attended DASD checker started
C600 4412 Storage management recovery started
C600 4414 LIC log started
C600 4416 Shutdown or programmed (CPM-related) IPL has started
Dedicated Service Tools (DST) SRCs for Attended IPLs:
C600 4500 Verifying network attributes
C600 4501 Looking for the console
C600 4502 Starting DST display task
C600 4503 Checking possible machine-readable information (MRI) on media
C600 4504 Verifying system serial number
C600 4505 Verifying system type
C600 4506 Verifying system-unique ID (OS/400 only
C600 4507 Starting 'before DST' DASD checker
C600 4508 Verifying system password (if DASD check OK; if not OK this is checked when
IPLing past DST)
C600 4509 Starting DASD migration function (only if migrating)
C600 450A Starting 'after DST' DASD checker (can happen twice)
C600 450C DST IPL status
Dedicated Service Tools (DST) SRCs for Unattended IPLs:
C600 4500 Verifying network attributes
C600 4504 Verifying system serial number
C600 4505 Verifying system type
C600 4506 Verifying system-unique ID (OS/400 only)
C600 4508 Verifying system password (if DASD check OK)
C600 450A Starting 'after DST' DASD checker
Licensed Internal Code (LIC) SRCs for IPLs:
C600 4A57 Parallel database recovery is at Pass 1
C600 4A60 Parallel database initialization is at Pass 1
C600 4B57 Parallel database recovery is at Pass 2
C600 4B60 Parallel database initialization is at Pass 2
C600 4C57 Parallel database recovery is at Pass 3
C600 4C60 Parallel database initialization is at Pass 3
C600 4F57 The system is recovering all database objects. This step can take several hours.
It can occur any time when database recovery is in progress.
C600 4F60 The system is examining all objects during database initialization. It can occur
any time when database initialization is in progress.
Note: At this point LIC initialization is complete, and operating system starts.
All hardware is verified.
OS/400 (only) operating system SRCs:
C900 2810 Reclaim machine context
C900 2820 Resolve system objects
C900 2825 Convert Work Control Block Table
C900 2830 System value object
C900 28C0 Prepare SPCF job
C900 28C5 Initialize system objects
C900 2910 Start system logging
C900 2920 Library and object information repository (OIR) cleanup
C900 2925 Verify POSIX** root directories
C900 2930 Database cross-reference
C900 2940 Console configuration
C900 2950 Install complex objects
C900 2960 Sign on processing
C900 2965 Software Management Services (SMS) initialization
C900 2967 Applying PTFs
C900 2968 IPL options
C900 2970 Database recovery part 1, journal recovery part 1
C900 2973 This recovery step attempts to perform any needed recovery for Database files
that were definitionally being changed, created or deleted when an abnormal
system end occurred.
C900 2976 This recovery step verifies the object recovery list performs any needed recovery
for Journals and Journal Receivers.
C900 2978 This IPL Status SRC is displayed when SRCs C900 2A70 - C900 2976 have been
completed
C900 2980 Storage requirements
C900 2990 Performance adjustments
C900 29A0 System control block
C900 29B0 Spool initialization
C900 29C0 Work control block table
C900 2A80 Before starting system jobs
C900 2A85 Bringing up POSIX SAG
C900 2A87 POSIX SAG restart and signals initialization
C900 2A90 Starting system jobs
C900 2A95 Abnormal Work Control Block Table cleanup
C900 2AA0 Damage Notification
C900 2AA1 This recovery step either rolls back or completes certain uncompleted Database
operations that were run under Commitment Control
C900 2AA2 This recovery completes certain Journal operations that were in
progress when the system ended processing
C900 2AA3 This recovery sends messages to QHST for Database files that may
have been damaged by a system end
C900 2AA3 This recovery sends messages to QHST for Database files that may
have been damaged by a system end
C900 2AA4 This IPL Status SRC is displayed when SRCs C900 2AA0 - C900 2AA3
have been completed
C900 2AA5 Integrated File System/New File System (NFS) directory recovery
C900 2AB0 Database Recovery part 2
C900 2AC0 Document Library Object (DLO) recovery
C900 2B10 Establish event monitors
C900 2B30 QLUS job
C900 2B40 Device configuration
C900 2C10 After system arbiter
C900 2C20 SNADS recovery
C900 2C25 ZMF component (Mail Enablement (OeDS) Framework) recovery
C900 2C40 Work Control Block Table cleanup
C900 2F00 IPL Complete
Operating system initialization is complete when the sign-on screen
displays on the console.
Thanks to Al Barsa, Jr.
|
|
Back
Backing up the IFS system
|
SAV DEV('/tap01') OBJ(('/*') ('/qsys.lib' *OMIT) +
('/qdls' *OMIT) ('/qibm/proddata' *OMIT) +
('/qca400' *OMIT) ('/qisafix' *OMIT) +
('/qopensys/qibm/proddata' *OMIT)) +
OUTPUT(*print) UPDHST(*YES)
The gotcha is with the device. /tap01 is a symbolic link without which
you'd have to type '/qsys.lib/tap01.devd'.
Thanks to Phil
|
|
Back
Null-terminated data - to do or not to do
|
However, since the inet_addr function is designed for C programs,
the string SHOULD be null-terminated. (correct me if I'm wrong!)
Therefore, my code would look like this:
D inet_addr PR 10I 0 ExtProc('inet_addr')
D DottedAddr 16A
C eval TcpAddr = %trim(TcpAddr) + x'00'
C eval sin_addr = inet_addr(tcpAddr)
This is right, but can be coded more easily if you are on V3R7 or greater
using a little-known parameter feature: OPTIONS(*STRING).
D inet_addr PR 10I 0 ExtProc('inet_addr')
D DottedAddr * VALUE OPTIONS(*STRING)
C eval sin_addr = inet_addr(%trim(tcpAddr))
Most "char *" parameters in C functions require null-terminated data. You can
handle the null-termination yourself, or you can ask the RPG compiler to do it
for you using OPTIONS(*STRING) on a pointer parameter passed by value. With
this type of parameter you can either pass a pointer or a character string. If
a character string, the compiler creates a temporary with your value followed by
a null character, and passes that instead.
Left as an exercise for the keen student: check out the %STR bif to see how to
handle pointers to null-terminated data within your RPG program without scanning
for x'00' and substringing.
Thanks to Barbara Morris
|
|
Back
The reason for semicolon on /Free specs?
|
Q: Why didn't you listen to the many lone voices about that stupid semicolon on /Free
specs?
A: You really want me to dredge up the logic behind that decision yet again? OK, here
goes. But first some history:
Back prior to V5R1, we had an enhancement survey where one of the items to be voted on
was free-form calcs. We thought at the time that it would be a big effort, and so a price tag
of $100 was given to it. In spite of the high cost, some voters actually blew their whole wad
on it! After thinking a bit more about the issue, I realised that the cost didn't have to be
that much, especially considering we really didn't have to worry anymore about some things
like conditioning indicators, resulting indicators, and definition of variables on the calc spec.
By V4R4, these things were generally considered to be bad style anyways. The issue of
multi-part factors remained, but that issue disappeared when we decided that the opcodes
that used multi-part factors could be replaced by existing or new built-in functions.
At this point, the implementation became much easier. The arguments are parsed and the
information about them placed into the same variables used to process them as if they were
coded on fixed-form calcs.
The biggest work in fact was implementing a new set of built-in functions to handle certain
opcodes that would not be allowed in free-form calcs, like LOOKUP, SCAN, and XLATE, as well
as the date/time/timestamp operations. But voters indicated that they wanted many of these
anyways, even without free-form calcs.
Then came the matter of syntax. At first, the design indicated free-form calcs with characters
CX in positions 6-7, with C+ indicating continuation. Later the CX was changed to CF, but the
principle remained the same. This was almost universally panned by RPG programmers, and
eventually we decided this had to be changed. At that time, I was working on another project,
but I was dragged back early to the RPG development team to change the design before it was
too late for V5R1.
So first, we decided that positions 6-7 of the free-form calc spec had to be blank. Then we had
to deal with the issue of continued statements.
But before we go further, here's one general principle in RPG language design: Since RPG runs
primarily on EBCDIC machines, and since various EBCDIC codepages have different code points
for different characters, the RPG character set is necessarily limited. That is, if for instance
we decided on the backslash as having a particular meaning in RPG, there may well be problems
in moving to different code pages.
So the question is: continuation character or end of statement delimiter?
The RPG language already had umpteen different styles of continuation. For instance, character
literals had two different styles of continuation, and numeric literals had their own different
style. We didn't want to use either '+' or '-' to indicate continuation since those would be too
easily confused with character literal continuation, as well as the binary addition, subtraction,
and catenation operators. Beyond those, there weren't really many good alternatives in the
available invariant EBCDIC characters. And besides, we didn't really want to introduce yet
another style of continuation.
Consider how continuation was already expressed in the Keywords entries and the
Extended-Factor-2 entry. No special continuation character was needed in those entries, since
continuation was indicated by blanks at the beginning of the continued spec. We felt that the
precedent of no continuation character was reasonable for the free-form calcs as well. Then,
the decision to select the semi-colon as the end of statement delimiter was a no-brainer, since
it was already very commonly used for that purpose.
The next decision was this: Was the end of statement delimiter needed for all calcs? That is,
in some languages, a semi-colon is not needed after some keywords, like ELSE. We decided
that the simplest rule to remember was that the semi-colon was needed after each and every
opcode. Thus, no exceptions to remember.
In conclusion, we certainly do appreciate that not everyone likes the choice of statement
delimiter style of free-form coding. (Practically all new things in the language have both fans
and detracters!) But hopefully, you now have some understanding of the process that led to
this particular design decision.
Thanks to Hans Boldt
|
|
Back
Debug doesn't show values for all fields in a file
|
Q: I'm trying to use the debugger and can't see all of my fields! Let me
explain. I have an RPG IV program that reads physical file Customer and prints a
report based on certain criteria. The validity of some of the information on the
report came into question, so I decided to use the debugger to see what was
causing the problem.
I placed a breakpoint in my program immediately after reading a record from file
Customer. I then tried to display the value of the fields the file contains.
Several of the fields were blank. Puzzled, I used DspPFM (Display Physical File
Member) to display the file. I was even more puzzled after this showed that the
record did indeed contain data in the fields reported as blank by the debugger!
Is there a problem with the debugger? Do I need PTFs?
A: There's not a problem with the debugger. The debugger isn't showing you a
value for the fields in question because the information isn't available to the
debugger. You see, the RPG compiler optimizes unreferenced fields out of your
program. In other words, any field in file Customer that is not specifically
referenced by an RPG operation isn't included in the program.
If you really want the unreferenced fields available to the debugger, you can
include an H-spec with keyword Debug. This prevents the compiler from optimizing
out unreferenced fields.
Thanks to Club Tech iSeries Newsletter
|
|
Back
Converting Num. Variables to Zero-Filled Char. in Free-Format
|
Q: With fixed-format RPG, I've always used the Move op-code to move a
numeric variable to a character variable. The resulting character variable
is right-justified and zero-filled. Now I'm beginning to work with free-
format RPG, and the Move op-code is not supported. I tried using the %Char
built-in function (BIF), but the result is not zero-filled and is left-
justified. What can I do in free-format RPG to convert a numeric variable to
a right-justified, zero-filled character variable?
A: There are several techniques you can use in free-format RPG to convert a
numeric variable to a right-justified, zero-filled character variable. I'll
show you several options.
In each of the following examples, Nbr is a nine-digit numeric variable with
a value of 12345, and the resulting character variable (Chr) is a nine-byte
character variable with a value of 000012345.
The following examples use the %Char BIF to convert Nbr to character. They
trim this intermediate character result and concatenate it to the end of a
string of character 0s.
This example explicitly concatenates a constant of nine 0s (the length of
the character field is 9).
D Nbr S 9P 0 Inz( 12345 )
D Chr S 9
/Free
EvalR Chr = '000000000' + %Trim( %Char( Nbr ) ) ;
/End-Free
The following example defines a nine-byte variable (Zero9) and initializes
it to all character 0s. This variable is then used in the concatenation
rather than using a constant as in the previous example.
D Nbr S 9P 0 Inz( 12345 )
D Chr S 9
D Zero9 S 9 Inz( *All'0' )
/Free
EvalR Chr = Zero9 + %Trim( %Char( Nbr ) ) ;
/End-Free
The next example defines a 30-byte variable (AllZero) and initializes it to
all character 0s. As in the previous example, this variable is used in the
concatenation. This is an improvement over the previous technique because 30
bytes is the maximum length for a numeric field. This single field,
therefore, can be used for any conversion.
D Nbr S 9P 0 Inz( 12345 )
D Chr S 9
D AllZero S 30 Inz( *All'0' )
/Free
EvalR Chr = AllZero + %Trim( %Char( Nbr ) ) ;
/End-Free
The following example uses another BIF, %EditC (Edit code), to perform the
desired conversion. I suggest this technique.
D Nbr S 9P 0 Inz( 12345 )
D Chr S 9
/Free
Chr = %EditC( Nbr : 'X' ) ;
/End-Free
Finally, you can use a data structure to perform the conversion. Simply
define a zoned numeric subfield in your data structure and set its value to
that of the number you wish to convert.
D Nbr S 9P 0 Inz( 12345 )
D Chr DS
D Nbr2 9S 0
/Free
Nbr2 = Nbr ;
/End-Free
Thanks to Club Tech iSeries Newsletter
|
|
Back
Service Programs -- The Chicken and The Egg
|
Q: I'm trying to create a few service programs and have a situation that I'm not sure
I can get out of! Here's the story...
I have service programs SrvPgm1, SrvPgm2, and SrvPgm3. SrvPgm1 references procedures
in SrvPgm2 and SrvPgm3. Normally, I would create service programs SrvPgm2 and SrvPgm3
to make their procedures available and then create service program SrvPgm1. However,
in this case, SrvPgm2 and SrvPgm3 also reference procedures in SrvPgm1. Therein lies
the chicken and the egg. To create SrvPgm1, I must first create SrvPgm2 and SrvPgm3;
to create SrvPgm2 and SrvPgm3, I must first create SrvPgm1!
If somebody knows which came first, the chicken or the egg, please let me know so that
I can get these service programs compiled!
A: Here's how you can solve your problem.
1. Create SrvPgm1 with Option(*UnrslvRef).
2. Create SrvPgm2 and SrvPgm3.
3. Recreate SrvPgm1 and do not specify Option(*UnrslvRef).
Thanks to Barbara Morris
|
|
Back
Finding Commands and Menus
|
Despite the logical naming convention for OS/400 commands and menus,
it's easy to get stymied while groping for the proper name.
Here are a few ways to easily find the command you want:
(1) Enter SLTCMD *ALL to display a list of all commands.
(2) Enter GO CMDxxxx, where xxxx is one or more characters, including
a generic name, which will show all command menus starting with
CMDxxxx. For example, CMDFI* will show two command menus, CMDFIL and
CMDFILE.
(3) Enter SLTCMD and a generic name to display a list of all commands
that contain one or more characters. For example, SLTCMD dspf* will
display all commands starting with DSPF, such as DSPF, DSPFAX, DSPFD,
and so on.
(4) Enter a generic name on the OS/400 command line (SLTCMD is assumed
by the system). For example, entering dspf* on the command line is
identical to entering SLTCMD dspf*.
It's preferable to use method 3 and not 4, since the "S" in SLTCMD is
close to the "D" on the keyboard, and with the right authority, you
could inadvertently perform a DLTCMD (Delete Command) operation. That
would be a bad thing.
Here are two easy ways to locate a menu:
(1) Enter GO *ALL, which displays all menus.
(2) Enter GO and a generic name to display a list of all menus that
contain one or more characters. For example, GO file* will display all
menus starting with FILE, such as FILE, FILESYS, FILETFR, and so on.
Notes to the text above:
I meant to say it was preferable to enter a generic name on the OS/400
command line instead of SLTCMD and a generic name.
(I had it backwards in the last issue.) For example, enter "dspf*"
instead of "SLTCMD dspf*". Omitting SLTCMD reduces the chances of
entering DLTCMD, which deletes commands -- a bad thing.
Also, Sandeep G. Bhat pointed out that to list all the major command
groups, you can use the following command:
GO MAJOR
Thanks to Andy Mahieu and Dedy Djajapermana and Club Tech iSeries Newsletter
|
|
Back
Sending Spooled Files To Another System
|
If you often need to send a spooled file to another system (e.g., an
iSeries or any other system that accepts File Transfer Protocol (FTP)
transfers), it's most common to use the SNDTCPSPLF (Send TCP/IP
Spooled File) command. There is another command, LPR (Send Spooled
File), that does exactly the same thing.
Here's an example of how to use it:
LPR RMTSYS(*AUST2) PRTQ(QPRINT) +
FILE(QPEZDISK) +
JOB(123456/DOOHANS/QPADEV0004) +
DESTTYP(*AS400)
This command sends the spooled file 'QPEZDISK' from user ID 'DOOHANS'
to the iSeries 'AUST2.'
Thanks to Sean Doohan
|
|
Back
Navigate Multiple CA Sessions More Quickly And Easily
|
You won't see any code in this tip, but if you're like most programmers who navigate
several Client Access sessions while programming, you'll find this tip useful.
It's not unusual for programmers to have many windows open at any given time. Those
that use SEU in Client Access sessions to edit their source frequently bounce from
one session to another. You can use the ALT TAB sequence to cycle through all of your
windows or you can create a shortcut that makes things simpler for you by cycling you
through Client Access sessions only.
In Client Access, select the option to customize your keyboard mapping. Pick a key
sequence (I like the Shift + End combination) that you want to use as your shortcut
and map it to the Jump Next function. Save your customization and from now on when
you want to navigate through your iSeries Client Access sessions, simply press your
shortcut key sequence.
Follow up:
The tip on Client Access navigation above generated considerable reader response.
Many of you wrote in to note that the Alt PageUp key sequence is the default keyboard
mapping for the Jump Next function in recent releases of Client Access. Others wrote
in to mention that another default key sequence in recent releases, Alt PageDown,
jumps to previous Client Access Sessions.
Still others prefer the Jump to Session function. This function lets you assign specific
sessions to specific key sequences so that you can navigate directly to sessions. For
example, some readers mentioned a scenario such as the following:
Session A is always an SEU edit session for QRPGLESrc.
Session B is always an SEU Session for QCLSrc.
Session C is always a session for WrkSplF.
The preferred keyboard mapping scheme follows:
Alt 1 -- Jump to Session A
Alt 2 -- Jump to Session B
Alt 3 -- Jump to Session C
I even received a note from a reader who customized the Client Access toolbar with
options for navigating between sessions! So many options...
Thanks to Club Tech iSeries Newsletter
|
|
Back
How to "squeeze" a field of spaces
|
C Eval string =
C 'String with blanks to strip'
C DoW %Scan( ' ': string ) > 0
C If %Scan( ' ': string ) >
C %Len( %TrimR( string ) )
C Leave
C EndIf
C Eval string =
C %Replace( '': string:
C %Scan( ' ': string ): 1 )
C EndDo
C string Dsply
Thanks to Gerry Tucker
|
|
Back
Get a command line from SysRq 3
|
WRKMSGD CPX2313 (*MSGF) in library QCPFMSG.
Change DSPJOB to WRKJOB and you have a CMD-line, when doing a system request 3.
|
|
Back
Get Host by Name & Get Host by Address
|
** Normally, I keep the following definitions as part of a larger
** member containing the definitions for all of the sockets API,
** called SOCKET_H, I copied the necessary stuff in-line to simplify
** this example code.
**
** To compile:
** CRTBNDRPG PGM(xxxx) SRCFILE(xxxx/xxxx) DFTACTGRP(*NO) +
** ACTGRP(*CALLER)
** (actually, activation group can be whatever you prefer)
**
** Disclaimer:
** This program is meant to be an "example", to help explain a
** programming technique. Although it works to the best of my
** knowledge, neither I, nor my employer will be held responsible
** for any damages that it may cause.
** -------------------------------------------------------------------
D* The "internet" address family.
** -------------------------------------------------------------------
D AF_INET C CONST(2)
** -------------------------------------------------------------------
** inet_addr()--Converts an address from dotted-decimal format
** to a 32-bit IP address.
**
** unsigned long inet_addr(char *address_string)
**
** Converts an IP address from format 192.168.0.100 to an
** unsigned long, such as hex x'C0A80064'.
**
** returns -1 on error
** -------------------------------------------------------------------
D INet_Addr PR 10U 0 ExtProc('inet_addr')
D char_addr 16A
** -------------------------------------------------------------------
** inet_ntoa()--Converts an address from 32-bit IP address to
** dotted-decimal format.
**
** char *inet_ntoa(struct in_addr internet_address)
**
** Converts from 32-bit to dotted decimal, such as, x'C0A80064'
** to '192.168.0.100'. Will return -1 on error
**
** -------------------------------------------------------------------
D inet_ntoa PR * ExtProc('inet_ntoa')
D ulong_addr 10U 0 VALUE
** -------------------------------------------------------------------
** "Special" IP Address values
** -------------------------------------------------------------------
D* any address availabl
D INADDR_ANY C CONST(0)
D* broadcast
D INADDR_BRO C CONST(4294967295)
D* loopback/localhost
D INADDR_LOO C CONST(2130706433)
D* no address exists
D INADDR_NON C CONST(4294967295)
** -------------------------------------------------------------------
** gethostbyname() -- Resolves a domain name to an IP address
**
** struct hostent *gethostbyname(char *host_name)
**
** struct hostent {
** char *h_name;
** char **h_aliases;
** int h_addrtype;
** int h_length;
** char **h_addr_list;
** };
**
** Returns a pointer to a host entry structure. The aliases and
** address list items in the structure are pointers to arrays of
** pointers, which are null terminated.
**
** -------------------------------------------------------------------
D GetHostNam PR * extProc('gethostbyname')
D HostName 256A
** -------------------------------------------------------------------
** gethostbyaddr()--Get Host Information for IP Address
**
** struct hostent *gethostbyaddr(char *host_address,
** int address_length,
** int address_type)
** struct hostent {
** char *h_name;
** char **h_aliases;
** int h_addrtype;
** int h_length;
** char **h_addr_list;
** };
**
** An IP address (32-bit integer formnat) goes in, and a
** hostent structure pops out. Really, kinda fun, if you
** havent already learned to hate the hostent structure, that is.
**
** -------------------------------------------------------------------
D GetHostAdr PR * ExtProc('gethostbyaddr')
D IP_Address 10U 0
D Addr_Len 10I 0 VALUE
D Addr_Fam 10I 0 VALUE
** -------------------------------------------------------------------
** Host Database Entry (for DNS lookups, etc)
**
** (this is a partial implementation... didn't try to
** figure out how to deal with all possible addresses
** or all possible aliases for a host in RPG)
**
** struct hostent {
** char *h_name;
** char **h_aliases;
** int h_addrtype;
** int h_length;
** char **h_addr_list;
** };
**
** #define h_addr h_addr_list[0]
** -------------------------------------------------------------------
D p_hostent S *
D hostent DS Based(p_hostent)
D h_name *
D h_aliases *
D h_addrtype 5I 0
D h_length 5I 0
D h_addrlist *
D p_h_addr S * Based(h_addrlist)
D h_addr S 10U 0 Based(p_h_addr)
D*** internal "work" variables. (not part of /COPY file)
D wkInput S 256A
D wkIP S 10U 0
D wkLen S 10I 0
D p_Name S * INZ(*NULL)
D wkName S 256A BASED(p_name)
C****************************************************************
C* Parameters:
C*
C* RetType: May be *NAME or *ADDR. If *NAME is given,
C* we'll return a domain name. If *ADDR we'll return an
C* IP Address.
C*
C* Input: Host or IP address to lookup. IP addresses should
C* be given in x.x.x.x format.
C*
C* Output: Resulting IP address, host name or error code.
C* Error codes are: *TYPE = invalid "RetType" parameter.
C* *BLANK = Input cant be blank
C* *FAIL = Lookup failed for this host.
C*
C* Note: This program is meant to be called from another
C* program, not from the command line. If you're
C* intending to call it from the command line, I'd recommend
C* making a simple command and CL front-end. (If you call
C* this program directly, OS/400 will mess up the long parms)
C****************************************************************
C *entry plist
c parm RetType 5
c parm Input 256
c parm Output 256
C* If we werent given enough parms, just end this program now...
C* (we'll seton LR, even) We can't return an error since we
c* don't have an output parm to return it in (ack!)
c if %parms < 3
c eval *inlr = *on
c return
c endif
C* Did we have a valid return type?
c if RetType <> '*NAME'
c and RetType <> '*ADDR'
c eval Output = '*TYPE'
c Return
c endif
C* Was some input given?
C if Input = *blanks
c eval Output = '*BLANK'
c Return
c endif
C* were we given an IP address or a name?
c eval wkInput = %trim(Input) + x'00'
c eval wkIP = inet_addr(wkInput)
C* An address was requested... and the input was already
C* an address... return the input directly.
C* (this is useful in an interactive application where the
C* calling program might not know if the address typed was
C* an IP address or a name)
c if RetType = '*ADDR'
c and wkIP <> INADDR_NON
c eval Output = %trim(Input)
c Return
c endif
C* Call the OS/400 resolver routines to get the information that
C* we require. (It will check the hosts table first, then try DNS)
c if wkIP = INADDR_NON
c eval p_hostent = gethostnam(wkInput)
c else
c eval p_hostent = gethostadr(wkIP:4:AF_INET)
c endif
c if p_hostent = *NULL
c eval Output = '*FAIL'
c return
c endif
C* if we're returning an address, we'll need to use inet_ntoa
C* to convert it back to dotted-decimal x.x.x.x format.
C*
c if RetType = '*ADDR'
c eval p_name = inet_ntoa(h_addr)
c if p_name = *NULL
c eval Output = '*FAIL'
c else
c x'00' scan wkName wkLen
c eval Output = %subst(wkName:1:wkLen-1)
c endif
c return
c endif
C* the hostent structure contains a pointer to the requested
C* domain name... we'll need to base a variable on that pointer,
C* and then convert it from the "C" format for strings to a
C* fixed-length RPG string
c if h_name = *NULL
c eval Output = '*FAIL'
c return
c endif
c eval p_name = h_name
c x'00' scan wkName wkLen
c eval Output = %subst(wkName:1:wkLen-1)
c return
Thanks to Scott Klement (I guess)
|
|
Back
Q: Does anyone know of a command or technique, that could be used to check for
the existence of an IFS file like CHKOBJ can check for the existence of a DB file?
A: As luck would have it, I wrote something like this a few months ago...
It's written in RPG IV, but designed to be used from CL commands in the same manner
that CHKOBJ is.
Member: CHKIFSOBJ
CMD PROMPT('Check IFS Object')
PARM KWD(OBJ) TYPE(*CHAR) LEN(120) MIN(1) +
CHOICE('Path Name') PROMPT('Name of IFS +
object')
PARM KWD(AUT) TYPE(*CHAR) LEN(10) RSTD(*YES) +
DFT(*NONE) VALUES(*NONE *EXCLUDE *RWX *RW +
*RX *R *WX *W *X) PROMPT('Authority')
Member: CHKIFSR4
** This is called by the CHKIFSOBJ command to check for
** an object in the IFS, and see if the user has authority
** to that object.
** SCK 04/02/01
** To compile:
** CRTBNDRPG PGM(xxx/CHKIFSR4) SRCFILE(xxx/xxx) DBGVIEW(*LIST)
** CRTCMD CMD(CHKIFSOBJ) PGM(xxx/CHKIFSR4) SRCFILE(xxx/xxxx)
**
**
H DFTACTGRP(*NO) ACTGRP(*NEW) BNDDIR('QC2LE')
D*****************************************************************
D* Access mode flags for access()
D*
D* F_OK = File Exists
D* R_OK = Read Access
D* W_OK = Write Access
D* X_OK = Execute or Search
D*****************************************************************
D F_OK C 0
D R_OK C 4
D W_OK C 2
D X_OK C 1
D*----------------------------------------------------------------
D* Determine file accessibility
D*
D* int access(const char *path, int amode)
D*
D*----------------------------------------------------------------
D access PR 10I 0 ExtProc('access')
D Path * Value Options(*string)
D amode 10I 0 Value
D c_error PR
D peErrMsg 128A const
D error PR
D peMsg 256A const
D wkExists S 1N INZ(*OFF)
D wkReadOk S 1N INZ(*OFF)
D wkWriteOk S 1N INZ(*OFF)
D wkSearchOk S 1N INZ(*OFF)
D wkPos S 10I 0
D peObject S 120A
D peAuthority S 10A
c eval *inlr = *on
C *entry plist
c parm peObject
c parm peAuthority
C* We got parms, right?
c if %parms < 2
c callp error('You must pass the OBJ ' +
c ' and AUT parms to this command')
c return
c endif
C* Validate AUT parm
c if peAuthority <> '*NONE'
c and peAuthority<>'*EXCLUDE'
c and peAuthority<>'*ALL'
c '*RWX' check peAuthority wkPos
c if wkPos > 1
c and %subst(peAuthority:wkpos)<>*blanks
c callp error('''' + peAuthority + ''' not ' +
c 'valid for parameter AUT.')
c return
c endif
c endif
C* Figure out user's access to the file:
c if access(%trim(peObject): F_OK) = 0
c eval wkExists = *On
c if peAuthority <> '*NONE'
c if access(%trim(peObject): R_OK) = 0
c eval wkReadOk = *On
c endif
c if access(%trim(peObject): W_OK) = 0
c eval wkWriteOk = *On
c endif
c if access(%trim(peObject): X_OK) = 0
c eval wkSearchOk = *On
c endif
c endif
c else
c callp c_error('access:')
c endif
C* For none, just see if the file exists:
c if peAuthority = '*NONE'
c if wkExists
c return
c else
c callp error('No file found, or you' +
c ' lack authority to it.')
c endif
c endif
C* If any authority found, user isn't excluded:
c if peAuthority = '*EXCLUDE'
c if wkReadOk = *On
c or wkWriteOk = *On
c or wkSearchOk = *On
c return
c else
c callp error('No file found, or you' +
c ' lack authority to it.')
c endif
c endif
C* Check read access:
c if %scan('R': peAuthority: 2)>1
c and not wkReadOk
c callp error('No file found, or you' +
c ' lack authority to it.')
c endif
C* Check write access:
c if %scan('W': peAuthority: 2)>1
c and not wkWriteOk
c callp error('No file found, or you' +
c ' lack authority to it.')
c endif
C* Check execute/search access:
c if %scan('X': peAuthority: 2)>1
c and not wkSearchOk
c callp error('No file found, or you' +
c ' lack authority to it.')
c endif
c return
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* Kill program and return an escape message that corresponds
* to the current ILE C error number.
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P c_error B
D c_error PI
D peErrMsg 128A const
D geterrno PR * ExtProc('__errno')
D strerror PR * ExtProc('strerror')
D errno 10I 0 value
D p_errno S *
D errno S 10I 0 based(p_errno)
c eval p_errno = geterrno
c callp error(%trimr(peErrMsg)+' ' +
c %str(strerror(errno)))
P E
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* Kill program and return an escape message
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P error B
D error 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 1A
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 wwMsgKey S 4A
D wwMsg S 52A
c callp SndPgmMsg('CPF9897': 'QCPFMSG *LIBL':
c peMsg: %len(peMsg): '*ESCAPE':
c '*PGMBDY': 1: wwMsgKey: dsEC)
c if dsECBytesA > 0
c eval wwMsg = dsECMsgID + ' occurred ' +
c 'calling QMHSNDPM API'
c dsply wwMsg
c endif
c return
P E
Thanks to Scott Klement
|
|
Back
1. You will need to know what jobq the job will be running in so you can hold the
jobq. Hold that job queue.
2. Submit the job that needs the debug.
3. Display the jobq to get the job name, user and job number. (debug job)
4. Issue the command STRSRVJOB and F4. Enter the debug job information and
press enter.
5. Issue the STRDBG command and F4 to enter the debug job information.
6. Release the jobq.
7. When the job start's to run a message will appear on the session that you
entered the STRSRVJOB command.
8. Press F10 and at the command line enter your ADDBKP command.
9. To resume after the break points are entered press F3 and when back on the
message press enter.
This will allow the job to run in batch and will act like the interactive version
of STRDBG.
10. When the job ends remember to ENDDBG and ENDSRVJOB.
Thanks to 'unknown'
Here is a simple technique for capturing the information on a screen and using
it in a program.
My motivation for developing the program below was to save typing when using the
STRSRVJOB command. I have recently had to debug many batch jobs. After having
issued WRKJOB and typed "STRSRVJOB 123456/USERNAME/JOBNAME" a hundred times,
I thought there must be some time-saving technique.
The program below is designed to be invoked from the WRKJOB screen. This screen
displays the job number, user, and job name; all required by many job-related
commands, such as STRSRVJOB. The program works by capturing the screen image
(using the Dynamic Screen Manager APIs), extracting the required job details,
and invoking the appropriate command.
The actual command string to be invoked is passed to the program by one of a
number of commands. Command SRV passes the string 'STRSRVJOB'. Command PRTLOG
passes the string 'DSPJOBLOG OPTION(*OUTPUT)'. The range of job-related commands
could easily be extended. Indeed, almost any command could be invoked, given an
appropriate screen to capture.
Program GETSCR:
H Dftactgrp(*NO)
H BndDir('QSNAPI')
* Dynamic Screen Manager prototypes...
* Create input buffer:
D CrtInpBuf pr 10i 0 Extproc('QsnCrtInpBuf')
D InitSize 10i 0 Const
D Increment 10i 0 Const Options(*OMIT)
D Maximum 10i 0 Const Options(*OMIT)
D InpBufHnd 10i 0 Const Options(*OMIT)
D ErrorCode 272 Options(*OMIT)
* Read screen without requiring AID key:
D ReadScreen pr 10i 0 Extproc('QsnReadScr')
D NoBytes 10i 0 Options(*OMIT)
D InpBufHnd 10i 0 Const Options(*OMIT)
D CmdBufHnd 10i 0 Const Options(*OMIT)
D EnvHnd 10i 0 Const Options(*OMIT)
D ErrorCode 272 Options(*OMIT)
* Retrieve pointer to buffer data:
D RtvDtaPtr pr * Extproc('QsnRtvDta')
D InpBufHnd 10i 0
D Data * Options(*OMIT)
D ErrorCode 272 Options(*OMIT)
* Delete buffer:
D DltBuf pr 10i 0 Extproc('QsnDltBuf')
D BufHnd 10i 0
D ErrorCode 272 Options(*OMIT)
D JobCommand s 32
D BufHnd s 10i 0
D NoBytes s 10i 0
D ReturnCode s 10i 0
D Screen ds Based(BufPtr)
D JobName 169 178
D JobUser 192 201
D JobNo 217 222
D SelName s Like(JobName)
D SelUser s Like(JobUser)
D CmdStr s 66
D CmdLen s 15 5 Inz(%Size(CmdStr))
C *Entry Plist
C Parm JobCommand
* Create input buffer.
C Eval BufHnd = CrtInpBuf (%Size(Screen) : *OMIT :
C *OMIT : *OMIT : *OMIT)
* Read screen.
C Eval NoBytes = ReadScreen (*OMIT : BufHnd :
C *OMIT : *OMIT : *OMIT)
* Retrieve pointer to buffer data.
C Eval BufPtr = RtvDtaPtr (BufHnd : *OMIT : *OMIT)
* Build Command string.
C x'00':' ' Xlate JobName SelName
C x'00':' ' Xlate JobUser SelUser
C Eval CmdStr = JobCommand + ' JOB(' +
C JobNo + '/' +
C %Trimr(SelUser) + '/' +
C %Trimr(SelName) + ')'
* Delete buffer.
C Eval ReturnCode = DltBuf (BufHnd : *OMIT)
* Execute command against job.
C Call 'QCMDEXC'
C Parm CmdStr
C Parm CmdLen
C Return
The commands below should be created to invoke the program above:
Command SRV:
CMD PROMPT('Start Service Job')
PARM KWD(COMMAND) TYPE(*CHAR) LEN(32) +
CONSTANT(STRSRVJOB)
Command PRTLOG:
CMD PROMPT('Print Job Log')
PARM KWD(COMMAND) TYPE(*CHAR) LEN(32) +
CONSTANT('DSPJOBLOG OPTION(*PRINT)')
Thanks to 'unknown'
|
|
Back
How File Overrides Really Work in ILE
|
When it comes to file overrides in ILE, there's plenty of speculation and
guesswork about how things work. Confusion about activation groups runs
rampant.
Because of this mass confusion, I dedicate an entire chapter to the subject
of file overrides in my book, "Starter Kit for the IBM iSeries and AS/400."
The information also appeared in "So You Think You Understand File
Overrides" in the July 2001 issue of NEWS/400. iSeries Network Professional
members can read the full article at
http://www.iseriesnetwork.com/artarchive/index.cfm?fuseaction=viewarticle&CO_
ContentID=10447&channel=art&subart=auth&authid=657 .
For now, I'd like to share with you the basic information you need in order
to understand just how file overrides work. With that, let's look at a few
rules that govern how file overrides are applied.
You're likely familiar with the fact that file overrides were affected by
the call levels within your job prior to the introduction of ILE. There is
an important call level rule that persists -- within a single call level,
only the most recent override is in effect. In other words, the most recent
override replaces the previous override in effect. This, coupled with the
fact that overrides are applied in decreasing call level sequence, explains
how overrides are applied in the OPM environment.
Things are a bit more complex in ILE because of the ways you can scope an
override. An override's scope determines the range of influence that the
override will have on your applications. You can scope an override to the
following levels:
* Call Level
A call-level override is at the level of the process that issues the
override, except that if the override is issued using a call to program
QCmdExc, the call level is that of the process that called QCmdExc. A
call-level override remains in effect from the time it is issued until
the system replaces or deletes it or until the call level in which the
override was issued ends.
* Activation Group Level
An activation-group-level override applies to all programs running in
the activation group associated with the issuing program, regardless of
the call level in which the override is issued. In other words, only the
most recently issued activation-group-level override is in effect. An
activation-group-level override remains in effect from the time the
override is issued until the system replaces it, deletes it, or deletes
the activation group. These rules apply only if the override is issued
from an activation group other than the default activation group.
Activation-group-level overrides issued from the default activation
group are scoped to call-level overrides.
* Job Level
A job-level override applies to all programs running in the job,
regardless of activation group or call level in which the override is
issued. Only the most recently issued job-level override is in effect. A
job-level override remains in effect from the time it is issued until
the system replaces or deletes it or until the job in which the override
was issued ends.
You specify an override's scope when you issue the override by using the
override command's OvrScope (Override scope) parameter.
ILE programs running in a named activation group can scope overrides to any
of these levels. However, programs (whether OPM or ILE) running in the
default activation group can scope overrides to only the job or call level.
The system processes the overrides for a file when it opens that file and
uses the following sequence to check and apply overrides:
1. call-level overrides up to and including the call level of the oldest
procedure in the activation group containing the file open (beginning
with the call level that opens the file and progressing in decreasing
call-level sequence)
2. the most recent activation-group-level overrides for the activation
group containing the file open (beginning with the call level that
opens the file and progressing in decreasing call-level sequence)
3. call-level overrides lower than the call level of the oldest procedure
in the activation group containing the file open (beginning with the
call level immediately preceding the call level of the oldest procedure
in the activation group containing the file open and progressing in
decreasing call-level sequence)
4. the most recent job-level overrides (beginning with the call level that
opens the file and progressing in decreasing call-level sequence)
If you remember nothing else about file overrides, remember this sequence of
applying overrides. I find that lack of knowledge of these steps accounts
for almost all file override problems as well as for the guesswork when
trying to determine or explain how file overrides really work.
Thanks to Club Tech iSeries Newsletter
|
|
Back
File Overrides Demystified
|
If you're like most, you've come across a situation in which the file overrides
in your application don't seem to be behaving the way you expect at one time or
another. After several attempts, you finally decide to change the override scope
to the job level so that the override you want will be in effect. While this
might produce the desired results, it's probably not the appropriate solution.
Application changes could result in unintentional behavior because of such a
widely scoped override.
The real answer is to understand how the system applies overrides. With that
understanding, not only can you achieve the desired behavior, but you can scope
also overrides appropriately. The rules governing the effect that overrides have
on your applications fall into three primary areas: the override scope,
overrides to the same file, and the order in which the system processes
overrides.
An override's scope determines the range of influence that the override will
have on your applications. You can scope an override to the following levels:
* Call level
A call-level override is at the level of the process that issues the
override, except that if the override is issued using a call to program
QCmdExc, the call level is that of the process that called QCmdExc. A call-
level override remains in effect from the time it is issued until the
system replaces or deletes it or until the call level in which the override
was issued ends.
* Activation group level
An activation-group-level override applies to all programs running in the
activation group associated with the issuing program, regardless of the call
level in which the override is issued. In other words, only the most
recently issued activation-group-level override is in effect. An activation-
group-level override remains in effect from the time the override is issued
until the system replaces it, deletes it, or deletes the activation group.
These rules apply only if the override is issued from an activation group
other than the default activation group. Activation-group-level overrides
issued from the default activation group are scoped to call-level overrides.
* Job level
A job-level override applies to all programs running in the job, regardless
of activation group or call level in which the override is issued. Only the
most recently issued job-level override is in effect. A job-level override
remains in effect from the time it is issued until the system replaces or
deletes it or until the job in which the override was issued ends.
You specify an override's scope when you issue the override by using the
override command's OvrScope (Override scope) parameter.
One feature of call-level overrides is the ability to combine multiple overrides
for the same file so that each of the different overridden attributes applies.
Consider the following program fragments:
ProgramA:
OvrPrtF File(Report) OutQ(Sales01) OvrScope(*CallLvl)
Call Pgm(ProgramB)
ProgramB:
OvrPrtF File(Report) Copies(3) OvrScope(*CallLvl)
Call Pgm(PrintPgm)
When program PrintPgm opens and spools printer file Report, the overrides from
both programs are combined, resulting in the spooled file being placed in output
queue Sales01 with three copies set to print.
Now, consider the following program fragment:
ProgramC:
OvrPrtF File(Report) OutQ(Sales01) OvrScope(*CallLvl)
OvrPrtF File(Report) Copies(3) OvrScope(*CallLvl)
Call Pgm(PrintPgm)
What do you think happens? You might expect this program to be functionally
equivalent to the two previous programs, but it isn't. Within a single call
level, only the most recent override is in effect. In other words, the most
recent override replaces the previous override in effect. In the case of
ProgramC, the Copies(3) override is in effect, but the OutQ(Sales01) override is
not. This feature provides a convenient way to replace an override within a
single call level without the need to first delete the previous override.
Consider the following program fragments:
ProgramA:
OvrPrtF File(Report) OutQ(Sales01) OvrScope(*CallLvl)
TfrCtl Pgm(ProgramB)
ProgramB:
OvrPrtF File(Report) Copies(3) OvrScope(*CallLvl)
Call Pgm(PrintPgm)
This latest change is identical to the first iteration of ProgramA and ProgramB,
except that rather than issue a Call to ProgramB from ProgramA, you use TfrCtl
to invoke ProgramB. It is noteworthy that TfrCtl doesn't start a new call level.
Instead, ProgramB will simply replace ProgramA on the call stack, thereby
running at the same call level as ProgramA. Because the call level doesn't
change, the overrides aren't combined. The point here is that contrary to common
belief, it's not the most recent override within a program that is in effect.
The rule is only the most recent override within a call level is in effect.
You've seen the rules concerning the applicability of overrides. In the course
of a job, many overrides may be issued. In fact, many may be issued for a single
file. When many overrides are issued for a single file, the system constructs a
single override from the overridden attributes in effect from all the overrides.
This type of override is called a merged override. Merged overrides aren't
simply the result of accumulating the different overridden file attributes,
though. The system must also modify or replace applicable attributes that have
been overridden multiple times, as well as remove overrides when an applicable
request to delete overrides is issued.
To determine the merged override, the system follows a distinct set of rules
that govern the order in which overrides are processed. You should first note
that the system processes the overrides for a file when it opens the file. The
system uses the following sequence to check and apply overrides:
1. call-level overrides up to and including the call level of the oldest
procedure in the activation group containing the file open (beginning with
the call level that opens the file and progressing in decreasing call-level
sequence)
2. the most recent activation-group-level overrides for the activation group
containing the file open
3. call-level overrides lower than the call level of the oldest procedure in
the activation group containing the file open (beginning with the call
level immediately preceding the call level of the oldest procedure in the
activation group containing the file open and progressing in decreasing
call-level sequence)
4. the most recent job-level overrides
For an example that demonstrates these rules, see "So You Think You Understand
File Overrides" in the July 2001 issue of iSeries NEWS. iSeries Network
Professional members can access the article online at
http://iseriesnetwork.com/resources/artarchive/index.cfm?fuseaction=viewarticle&CO_
ContentID=10447&channel=art&PageView=Search .
In some cases, you may want to protect an override from the effect of other
overrides to the same file. In other words, you want to ensure that an override
issued in a program is the override that will be applied when you open the
overridden file. You can protect an override from being changed by overrides
from lower call levels, the activation group level, and the job level by
specifying Secure(*Yes) on the override command.
This tip is excerpted from Chapter 21, "So You Think You Understand File
Overrides," in "Starter Kit for the IBM iSeries and AS/400" from 29th Street
Press (and the article which appeared in the July 2001 issue of iSeries
Thanks to Club Tech iSeries Newsletter
|
|
Back
Mean Absolute Deviation (MAD)
|
Assuming you mean MAD as defined by www.xycoon.com/mad.htm, here's an RPG
procedure to compute it.
Note that although it compiles, I haven't actually tried it with real data.
I'll leave the debugging (and conversion to a release prior to V5R3) up to you.
P mad b export
D mad pi 8f
D data 8f dim(1000) options(*varsize)
D num 10i 0 value
D sum s 8f
D avg s 8f
D i s 10i 0
/free
// compute average
avg = %xfoot(%subarr(data:1:num)) / num;
// Compute sum of absolute deviations
sum = 0;
for i = 1 to num;
sum += %abs(data(i)-avg);
endfor;
// return mean average absolute devation
return sum / num;
/end-free
P mad e
Thanks to Hans Boldt
|
|
Back
I have seen on this forum a sustained interest for "What's new in V5R3".
The Information Center is of help in some extent (for example, you can get
a list of changed commands, but not directly the change itself).
Due to my job (I'm a teacher). I have to track what really changed in the
OS/400 commands. Hereunder is the result.
ADDIMGCLGE ... FROMFILE(*NEW) ... IMGSIZ
ADDOPTCTG ... MEDLOC(*IOSTATION/*MAGAZINE)
ADD/CHGPJE ... THDRSCAFN ... RSCAFNGRP
ADD/CHGRTGE ... THDRSCAFN ... RSCAFNGRP
ADDTRCFTR ... JVATRG
APY/RMVJRNCHG ... OBJ(*ALLJRNOBJ) ... FROMENTLRG ... TOENTLRG ... OPTION
... OBJERROPT ... OUTPUT ... OUTFILE ... OUTMBR ... DETAIL
CALLPRC ... PARM(&PARM *BYREF|*BYVAL)
CFGTCPAPP APP(*NTP)
CHGATR ATR(*CRTOBJSCAN, *SCAN, *ALWSAV, *RSTDRNMUNL, *SETUID, *SETGID)
CHG/CRTCRG ... EXITPGMFMT
CHG/CRTDEVPRT ... MFRTYPMDL(*INFOPRINT2085, *INFOPRINT2105)
CHGIMGCLGE ... WRTPTC
CHG/CRTJOBD ... DDMCNV
CHG/CRTJRN ... RCVSIZOPT(*MAXOPT3)
CHG/CRTLINETH ... ASSOCPORT
CHGNTPA ... SVRAUTOSTR ... SVRACTLOG ... SYNCRQD
CHG/CRTNWSD ... SHUTDTIMO ... PWRCTL
CHGOPTA ... EXTMEDFMT
CHG/CRTPSFCFG ... PDFADMIN ... PDFMAPPGM(*IBMPGM) ... PDFMAP ... AFPSAVE
... AFPOUTQ
CHGRCYAP SYSRCYTIME(min 1)
CHGSPLFA/DLT/HLD/RLS/WRKSPLF ... ASPDEV
CHGTCPA ... ECN
CHG/CRTUSRPRF ... LCLPWDMGT ... EIMASSOC
CHKOBJITG ... SCANFS
CMPJRNIMG/DSPJRN/RCVJRNE ... FROMENTLRG ... TOENTLRG ... CCIDLRG
CPYPTFGRP ... DTACPR ... CPYPTF ... RPLSPR ... COVER
CRTCTLxxx/DEVxxx/LINxxx etc ... AUT(*CHANGE)
CRTDEVCRP ... APPTYPE
CRTDIR/CRTUDFS ... CRTOBJSCAN ... RSTDRNMUNL
CRTDTAARA/DTAQ ... RMTLOCNAME(*RDB) ... RDB
CRTJRNRCV ... THRESHOLD(15000000)
CRTNWSSTG ... ASPDEV
CVTDIR OPTION(*CHGPTY) ... RUNPTY
DCL ... TYPE(*INT|*UINT) LEN(2|4)
DCL ... TYPE(*CHAR) LEN(max 32767)
DCLF/RCVF/SNDF/SNDRCVF/WAIT ... OPNID
DLTUSRPRF ... EIMASSOC
DUPOPT ... ALWMEDERR ... OUTPUT
ENDSBS ... BCHTIMLMT
STR/ENDTCPSVR *DCE and *NSMI removed
INSPTF ... PMTMED
JAVA/RUNJVA ... AGTPGM ... AGTOPTIONS ... JOB
RCLSTG ... OMIT(*DIR)
RGZPFM ... RBDACCPTH ... ALWCANCEL ... LOCK
RMVJRNCHG ... TOENT(*COMMITSTART)
RMVMSG/SNDRPY ... RJTDFTRPY
RST ... PATTERN
RSTCFG ... OMITOBJ
RSTLIB ... SAVLIB(*ANY) ... OMITOBJ
RSTOBJ ... SAVLIB(*ANY|generic|list) ... OMITLIB ... OMITOBJ
RTVJOBA ... DATETIME ... TIMZON ... TIMZONABBR ... TIMZONFULL ... TIMOFFSET
... THDRSCAFN ... RSCAFNGRP
RTVJRNE ... FROMENTLRG ... TOENTLRG ... CCIDLRG ... RTNSEQLRG
RTVUSRPRF ... LCLPWDMGT
RUNSQLSTM ... SQLCURRULE ... DECRESULT
SAV/SAVRST ... PATTERN ... SCAN
SAV/SAVOBJ/SAVLIB/SAVCHGOBJ/SAVCFG/SAVSECDTA/SAVDLO/SAVSYS
... DTACPR(*LOW/*MEDIUM/*HIGH)
SAVLIB/SAVOBJ/SAVCHGOBJ/SAVRSTLIB/SAVRSTOBJ/SAVRSTCHG ... ACCPTH(*SYSVAL)
SAVLIB ... SAVACTWAIT is a list of 3
STRCMNTRC/TRCCNN/TRCTCPAPP ... WCHMSG ... WCHMSGQ ... WCHJOB ... WCHLICLOG
... WCHTIMO ... TRCPGM ... TRCPGMITV
STRTCP ... STRPTPPRF
STRTCPSVR ... NTPSRV
STRTRC ... TRCTYPE(*IFS) ... JOBTYPE ... WCHMSG ... WCHMSGQ ... WCHJOB
... WCHLICLOG ... WCHTIMO ... TRCPGM ... TRCPGMITV
TRCINT ... OUTPUT ... OUTFILE ... OUTMBR ... WCHMSG ... WCHMSGQ ... WCHJOB
... WCHLICLOG ... WCHTIMO ... TRCPGM ... TRCPGMITV
Thanks to Richard THEIS
|
|
Back
Page #2
Page #4