× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.


  • Subject: An introduction to MI by example...
  • From: "Phil Hall" <hallp@xxxxxxxx>
  • Date: Tue, 9 Nov 1999 14:40:25 -0600

Hello All,

Many of you probably saw Leif's test program, the code for which he
posted, to retrieve the machine serial number. Well, for those of you on
this list who are still MI challenged, and are waiting to learn
something, let's introduce you to MI, by breaking down Leif's code. You
should also read this in conjunction with the System API Reference
Manual, chapter 67, Program and CL Command APIs section. This section
describes the syntax for MI programs and will expand on the usage of the
definitions.

Here's the original code:

DCL SPCPTR .MACHINE-ATTR INIT(MACHINE-ATTR);
DCL DD      MACHINE-ATTR CHAR(2608) BDRY(16);
    DCL DD  MAT-MAX-SIZE   BIN(4) DEF(MACHINE-ATTR) POS(1) INIT(2608);
    DCL DD  MAT-ACT-SIZE   BIN(4) DEF(MACHINE-ATTR) POS(5);
    DCL DD  MAT-P-SNBR   CHAR(10) DEF(MACHINE-ATTR) POS(1125);

ENTRY * EXT;
    MATMATR  .MACHINE-ATTR, X'012C';
    CPYBLAP   MSG-TEXT, MAT-P-SNBR, " ";
    CVTHC     MSG-TEXT-HEX, MAT-P-SNBR;
    CALLI     SHOW-MESSAGE, *, .SHOW-MESSAGE;
    RTX       *;

/* SHOW A MESSAGE */

DCL SYSPTR .SEPT(6440) BAS(PCO-POINTER);
DCL SPC PROCESS-COMMUNICATION-AREA  BASPCO;
    DCL SPCPTR PCO-POINTER DIR;

DCL SPCPTR .MSG-ID   INIT(MSG-ID);
DCL DD      MSG-ID   CHAR (7) INIT("       ");

DCL SPCPTR .MSG-FILE INIT(MSG-FILE);
DCL DD      MSG-FILE CHAR(20) INIT("                    ");

DCL SPCPTR .MSG-TEXT INIT(MSG-TEXT);
DCL DD      MSG-TEXT CHAR(40);
    DCL DD  MSG-TEXT-HEX CHAR(20) DEF(MSG-TEXT) POS(20);

DCL SPCPTR .MSG-SIZE INIT(MSG-SIZE);
DCL DD      MSG-SIZE BIN( 4)  INIT(40);

DCL SPCPTR .MSG-TYPE INIT(MSG-TYPE);
DCL DD      MSG-TYPE CHAR(10) INIT("*INFO     ");

DCL SPCPTR .MSG-QS   INIT(MSG-QS);
DCL DD      MSG-QS   CHAR(20) INIT("*REQUESTER          ");

DCL SPCPTR .MSG-QSN  INIT(MSG-QSN);
DCL DD      MSG-QSN  BIN( 4)  INIT(1);

DCL SPCPTR .REPLY-Q  INIT(REPLY-Q);
DCL DD      REPLY-Q  CHAR(20) INIT("                    ");

DCL SPCPTR .MSG-KEY  INIT(MSG-KEY);
DCL DD      MSG-KEY  CHAR( 4);

DCL SPCPTR .ERR-CODE INIT(ERR-CODE);
DCL DD      ERR-CODE BIN( 4) INIT(0);

DCL OL QMHSNDM (.MSG-ID,   .MSG-FILE, .MSG-TEXT, .MSG-SIZE,
                .MSG-TYPE, .MSG-QS,   .MSG-QSN,  .REPLY-Q,
                .MSG-KEY,  .ERR-CODE)  ARG;

DCL INSPTR .SHOW-MESSAGE;
ENTRY       SHOW-MESSAGE INT;
        CALLX     .SEPT(4268), QMHSNDM, *; /* SEND MSG TO MSGQ */
        B         .SHOW-MESSAGE;

PEND;


OK, still with me ? Good, let's begin...


Let's look at the first 5 lines;

    DCL SPCPTR .MACHINE-ATTR INIT(MACHINE-ATTR);
    DCL DD      MACHINE-ATTR CHAR(2608) BDRY(16);
        DCL DD  MAT-MAX-SIZE   BIN(4) DEF(MACHINE-ATTR) POS(1)
INIT(2608);
        DCL DD  MAT-ACT-SIZE   BIN(4) DEF(MACHINE-ATTR) POS(5);
        DCL DD  MAT-P-SNBR   CHAR(10) DEF(MACHINE-ATTR) POS(1125);

Those of you  know RPG, may actually see some similarity, if you look
hard enough.

The first line declares a variable of type SPCPTR [a OS/400 space
pointer] called '.MACHINE-ATTR' and the pointer is initialized with the
address of a something called 'MACHINE-ATTR'.

The next 4 lines define what that something called 'MACHINE-ATTR' is.
This time the code is declaring a 'scalar-data-object' called
'MACHINE-ATTR' of type CHAR, size 2608, that is on a 16 byte boundary
with three other variables defined across it. No, stop right there.
Don't move this email to your deleted mail folder. It's not as bad as it
looks, really. If you were to think in RPG, look at those four lines
again. Look familiar ? What if I was to say that the following RPG is
basically the same;

D MACHINE-ATTR    DS          2608
D  MAT-MAX-SIZE           1      4B 0 Inz(2608)
D  MAT-ACT-SIZE           5      8B 0
D  MAT-P-SNBR                   16A   Overlay(MACHINE-ATTR:1125)

And the very first line of the MI program could be written as;

D .MACHINE-ATTR   S               *   Inz(%Addr(MACHINE-ATTR))

See, not that bad after all. OK, on with the next bit of code.

    ENTRY * EXT;
        MATMATR  .MACHINE-ATTR, X'012C';
        CPYBLAP   MSG-TEXT, MAT-P-SNBR, " ";
        CVTHC     MSG-TEXT-HEX, MAT-P-SNBR;
        CALLI     SHOW-MESSAGE, *, .SHOW-MESSAGE;
        RTX       *;

OK, the first line of this section should be easy, it's an entry point -
we've finally reached some real code !. The entry point definition in
this code is specifying a unnamed entry point, by using '*', and that
this entry point will be externally visible, by using the 'EXT'
directive. Now, don't get too brave, all subroutines in MI also use the
same syntax, as we'll see later, but generally only one will be unnamed
(as it's difficult to jump to an unnamed subroutine !) and this one can
then normally be assumed to be the program entry point.

So we've found the program entry point, what's next ? Well, welcome to
your first MI instruction - MATMATR. This instruction is documented in
the 'MI Functional Reference' and also in the 'ILE/C MI Library
Reference' manuals. Basically it MATerializes Machine ATtRibutes, which
really means it retrieves data about the AS/400 from various different
locations on the machine and combines them into one huge great block of
data.

But hold on, what's that X'012C' business ? Well, to limit the amount of
data returned from the instruction (this is a beast of an instruction
and has over 30 pages for it in the manual), you can select what kind of
data is to be materialized. In this case, X'012C' means 'return the
vital product info' which among other things will return the serial
number.

So to recap, the MATMATR instruction is being called to materialize just
the vital product information into the .MACHINE_ATTR variable.

Then we have the CPYBLAP instruction, again reading the manual is
recommended, but basically this instruction means 'CoPY Bytes
Left-Adjusted with Pad' so we're moving data from MAT-P-SNBR into the
left most part of MSG-TEXT and padding anything left over in MSG-TEXT
with " ". To illustrate this, if MAT-P-SNBR contains 'ABCDEF' and
MSG-TEXT contains 'XXXXXXXXX', after the instruction CPYBLAP, MSG-TEXT
will hold 'ABCDEF    '

Following this, we have a CVTHC instruction, ConVerT Hex to Character,
which is used in this code to convert the MAT-P-SNBR from hex to
character and store the converted data in MSG-TEXT-HEX.

Next up is a CALLI instruction, CALL Internal, which calls a subroutine,
defined in the source. The syntax for CALLI is;

CALLI <entry-point-name> <args> <return-target>

So in this code, we're calling subroutine SHOW-MESSAGE, with no args (as
specified by using '*'), and the return target from the call to
SHOW-MESSAGE is to be the location pointed to by the instruction pointer
.SHOW-MESSAGE. This <return-target> operand allows you to jump all over
the code, but we'll leave that for another day.

Finally in this section of code, we have a RTX *. This means ReTurn
External, and in our example code will end the program.

AUK, the next 3 lines of code;

    DCL SYSPTR .SEPT(6440) BAS(PCO-POINTER);
    DCL SPC PROCESS-COMMUNICATION-AREA  BASPCO;
       DCL SPCPTR PCO-POINTER DIR;

Are there to look up the program QMHSNDM via the SEPT, which is the
System Entry Point Table - a table on the AS/400 that contains a list of
some of the callable IBM API's - from a pointer in the current jobs
process communication area.

Following this is a series of;

    DCL SPCPTR .MSG-ID   INIT(MSG-ID);
    DCL DD      MSG-ID   CHAR (7) INIT("       ");

Which are declaring variables, and declaring pointers to these
variables. After all the variables have been declared, we hit the
following lines of code;

    DCL OL QMHSNDM (.MSG-ID,   .MSG-FILE, .MSG-TEXT, .MSG-SIZE,
                    .MSG-TYPE, .MSG-QS,   .MSG-QSN,  .REPLY-Q,
                    .MSG-KEY,  .ERR-CODE)  ARG;

Which is setting up the argument list, called QMHSNDM, needed when
calling the QMHSNDM API.

Next we have;

    DCL INSPTR .SHOW-MESSAGE;

Remember the .SHOW_MESSAGE return target in the CALLI instruction ? Well
this is the instruction pointer .SHOW_MESSAGE being defined, but note
it's not being initialized with anything, we'll see why in a moment.

Finally we have;

    ENTRY       SHOW-MESSAGE INT;
            CALLX     .SEPT(4268), QMHSNDM, *; /* SEND MSG TO MSGQ */
            B         .SHOW-MESSAGE;

Which is the SHOW-MESSAGE subroutine we were calling in the CALLI. This
subroutine calls, using the CALLX instruction, the program number 4268
in the SEPT, which turns out to be QMHSNDM, passing the argument list
QMHSNDM. The next line of code is one of those weird things in MI
programming. It's a branch instruction, branching to instruction pointer
.SHOW-MESSAGE, which due to the weirdness on MI actually causes the
subroutine to return to the place where it was called from. In our
example this is back to the RTX instruction after the CALLI instruction.

The very last line of code;

    PEND;

is just there really to keep the compiler happy !


There we have it, one MI program that you understand - crack open those
MI manuals, and read some more !

--phil

+---
| This is the MI Programmers Mailing List!
| To submit a new message, send your mail to MI400@midrange.com.
| To subscribe to this list send email to MI400-SUB@midrange.com.
| To unsubscribe from this list send email to MI400-UNSUB@midrange.com.
| Questions should be directed to the list owner/operator: dr2@cssas400.com
+---


As an Amazon Associate we earn from qualifying purchases.

This thread ...

Follow-Ups:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.