Examples
Example 7. Print Routine
One problem with using Metal-C is that there are no I/O routines. When writing stand alone programs in Metal-C, I have wanted to at least have the ability to print messages. This could be accomplished by having an Assembler libray of routines for I/O. Not wanting to have to create a separate library of Assembler I/O routines, I came up with the routine below, which works for simple print cases.
Struct DCB
The struct dcb is common to all routines. It contains dcb, storage, and environment information. At program start, it is declared and intialized as in this example:
int rc;
int i;
struct dcb _dcb; // Allocation
char message[133];
rc = 0;
memset(&_dcb, 0, sizeof(struct dcb)); // Initialize to all x'00's
memcpy(_dcb.ddname, "SYSPRINT", 8); // DDNAME to Open
_dcb.lrecl = 133; // LRECL
_dcb.blksize = 1330; // BLKSIZE
memset(&message, ' ', sizeof(message));
sprintf((char*)&message, "The value of i=%i",i);
_dcb.currentRecord = &message; // Set address of text to print
// Routines to Invoke for Printing
rc = init(&_dcb);
rc = open(&_dcb);
rc = put(&_dcb);
rc = close(&_dcb);
rc = term(&_dcb);
struct storage
{
char dcb[96];
} ;
struct dcb
{
char ddname[8];
int lrecl;
int blksize;
void *storage; // Pointer to z/OS DCB
int size;
void *currentRecord; // Pointer to current output string
void *token;
__csysenv_t _envtkn; // Metal C Environment Token
} ;
Type Signatures
extern int init(struct dcb *_dcb); extern int term(struct dcb *_dcb); extern int open(struct dcb *_dcb); extern int put(struct dcb *_dcb); extern int close(struct dcb *_dcb);
Signature Details
- init() – Create Metal C Environment
- This routine is invoked once per program execution. It initializes the Metal-C runtime environment. This environment is used when calling Metal-C functions that require an environment, such as those related to storage management and other functions, e.g. malloc(), free, sprintf(), etc. Storage for the environment structure is obtained by using the attributes specified in the input csysenv structure. Not all Metal-C functions require this environment to be set up. In this case I am using the sprintf function which requires the environment. To determine which functions require the Metal-C environment to be established see z/OS Metal C Programming Guide and Reference©, Chapter 3. C functions available to Metal C programs.
- term() – Terminate Metal C Environment
- This routine is invoked once per program execution. It terminates the Metal-C runtime environment.
- open() – Open File for Output
- This routine is normally invoked once per program execution. It performs an OPEN of the dcb to be used for printing.
- close() - Close File
- This routine is normally invoked once per program execution. It performs a CLOSE of the dcb that was opened.
- put() - Write a Character String to File
- This routine is invoked for every desired print operation. It performs a PUT to the output file specified by the dcb.
C Source
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ihadcb.h"
#ifndef __MVS__
#include <stdbool.h>
#define __CSE_CURRENT_VERSION __CSE_VERSION_1
#define __CSE_VERSION_1 1
#include "env.h"
__csysenv_t __cinit(struct __csysenv_s * csysenv);
void __cterm(__csysenv_t csysenvtkn);
#endif
#ifdef __MVS__
#pragma export(init)
#pragma export(open)
#pragma export(put)
#pragma export(close)
#pragma export(term)
#endif
#define true 1
#define false 0
#ifdef __MVS__
#pragma insert_asm("MODELDCB DCB DDNAME=MODELDCB,MACRF=PM,DSORG=PS")
#endif
struct storage
{
char dcb[96];
} ;
struct dcb
{
char ddname[8];
int lrecl;
int blksize;
void *storage;
int size;
void *currentRecord;
void *token;
__csysenv_t _envtkn;
} ;
extern int init(struct dcb *_dcb)
{
int returnCode;
returnCode = 0;
#ifdef __MVS__
struct __csysenv_s _sysenv;
/* The __cinit() function establishes a Metal C
environment based on the characteristics in the input
csysenv structure.*/
// Initialize the csysenv structure.
memset(&_sysenv, 0x0, sizeof(_sysenv));
_sysenv.__cseversion = __CSE_VERSION_1;
// Set heap initial and increment sizes.
_sysenv.__cseheap31initsize = 65536;
_sysenv.__cseheap31incrsize = 8192;
_sysenv.__cseheap64initsize = 20;
_sysenv.__cseheap64incrsize = 1;
// Create a Metal C environment. */
_dcb->_envtkn = __cinit(&_sysenv);
#endif
#ifdef __MVS__
__asm(" ST 15,%0 "
: "=m"(_dcb->token)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int term(struct dcb *_dcb)
{
int returnCode;
int storageSize;
void *storagePtr;
returnCode = 0;
storageSize = _dcb->size;
storagePtr = _dcb->storage;
#ifdef __MVS__
__asm( (" STORAGE RELEASE"
",LENGTH=(%0)"
",ADDR=(%1)")
:
: "r"(storageSize), "r"(storagePtr)
: "r0", "r1", "r14", "r15"); // clobber list
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
#ifdef __MVS__
__cterm((__csysenv_t) _dcb->_envtkn);
#endif
return returnCode;
}
extern int open(struct dcb *_dcb)
{
int storageSize;
char wrkarea[256];
int returnCode;
struct storage *_storage;
struct ihadcb *_ihadcb;
returnCode = 0;
storageSize = 96;
// DCB must reside below the line in storage.
#ifdef __MVS__
__asm( (" STORAGE OBTAIN,LOC=BELOW"
",LENGTH=(%1)"
",ADDR=%0")
: "=m"(_dcb->storage)
: "r"(storageSize)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
__asm(" ST 0,%0 "
: "=m"(_dcb->size)
:
: "r0", "r1", "r14", "r15");
#endif
_storage = _dcb->storage;
memset(wrkarea, 0, sizeof(wrkarea));
wrkarea[0] = 0x80;
#ifdef __MVS__
__asm(" MVC 0(96,%0),MODELDCB"
:
: "r"(_storage->dcb)
: "r0", "r1", "r14", "r15");
#endif
_ihadcb = (void*) _storage->dcb;
memcpy(_ihadcb->dcbddnam, _dcb->ddname, 8);
_ihadcb->dcblrecl = _dcb->lrecl;
_ihadcb->dcbblksi = _dcb->blksize;
#ifdef __MVS__
__asm( (" OPEN (%1,(OUTPUT)),MODE=31,MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(_storage->dcb)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int put(struct dcb *_dcb)
{
char wrkarea[256];
int returnCode;
void *outputPtr;
struct storage *_storage;
returnCode = 0;
_storage = _dcb->storage;
outputPtr = _dcb->currentRecord;
#ifdef __MVS__
__asm( (" PUT (%0),(%1)")
:
: "r"(_storage->dcb), "r"(outputPtr)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int close(struct dcb *_dcb)
{
int storageSize;
char wrkarea[256];
int returnCode;
struct storage *_storage;
_storage = _dcb->storage;
memset(wrkarea, 0, sizeof(wrkarea));
wrkarea[0] = 0x80;
#ifdef __MVS__
__asm( (" CLOSE (%1),MODE=31,MF=(E,%0)")
: "=m"(wrkarea[0])
: "m"(_storage->dcb)
: "r0", "r1", "r14", "r15"); // clobber list"
__asm(" ST 15,%0 "
: "=m"(returnCode)
:
: "r0", "r1", "r14", "r15");
#endif
return returnCode;
}
extern int main(int argc, char** argv)
{
int rc;
int i;
struct dcb _dcb;
char message[133];
rc = 0;
memset(&_dcb, 0, sizeof(struct dcb));
memcpy(_dcb.ddname, "SYSPRINT", 8);
_dcb.lrecl = 133;
_dcb.blksize = 1330;
i = 12345;
memset(&message, ' ', sizeof(message));
sprintf((char*)&message, "The value of i=%i",i);
_dcb.currentRecord = &message;
rc = init(&_dcb);
rc = open(&_dcb);
rc = put(&_dcb);
rc = close(&_dcb);
rc = term(&_dcb);
return rc;
}