Preinitializing a C program

Figure 1 is a sample preinitialized C program that shows how to do the following:

The parameters it expects are the file name in argv[1] and the return code in argv[2]. The C program printf()s the value of the return code, writes a record to the file name, and decrements the value in return code.

The assembler program that drives the C program establishes the C environment and repeatedly invokes the C program, initially passing a value of 5 in the return code. When the return code set by the C program is zero, the assembler program terminates the C environment and exits.

Program CCNGCA6 (Figure 1 ) does not include the logic that would verify the correctness of any of the invocations. Such logic is imperative for proper operations.

Figure 1. Preinitializing a C program (CCNGCA6)
CCNGCA6 TITLE 'TESTING PREINITIALIZED C PROGRAMS'
***-------------------------------------------------------------
***     this example shows how to preinitialize a C program
***     part 1 of 3 (other files are CCNGCA7 and CCNGCA8)
***     Function: Demonstrate the use of Preinitialized C programs
***     Requests used:  INIT, CALL, TERM
***     Parameters to C program: FILE_NAME, RUN_INDEX
***     Return from C Program: RUN_INDEX
***-------------------------------------------------------------
CCNGCA6 CSECT
CCNGCA6 RMODE ANY
CCNGCA6 AMODE ANY
         EXTRN CEESTART            C Program Entry
         STM   R14,R12,12(R13)     Save registers
         BALR  R3,0                Set base register
         USING *,R3                Establish addressability
         ST    R13,SVAR+4          Set back chain
         LA    R13,SVAR            Set this module's save area
***-------------------------------------------------------------
***      Initialize
***-------------------------------------------------------------
P_INIT   DS    0H
         MVC   P_RQ,INIT           Set INIT as the request
         LA    R1,PALIPT           Load Parameter pointer
         L     R15,CEP             Load C Entry Point
         BALR  R14,R15             Invoke C Program
***-------------------------------------------------------------
***      The C environment has been established.
***      Parameters include RUN_INDEX which will be counted down
***      by the C program.  When the RUN_INDEX is zero, termination
***      will be requested.
***      The following code will set up C program parameters and
***      CALL request, invoke the C program and test for termination.
***-------------------------------------------------------------
         LA    R1,PGPAPT           Pointer to C program parameters
         ST    R1,EP_PGPA          ... to extended parameter list
DO_CALL  DS    0H
         MVC   P_RQ,CALL           set up CALL request
         LA    R1,PALIPT           set parameter pointer
         L     R15,CEP             set entry point
         BALR  R14,R15             invoke C program
         L     R0,RUN_INDEX        Test Return Code
         LTR   R0,R0
         BNZ   DO_CALL             Repeat CALL
***-------------------------------------------------------------
***      C requested termination.
***      Set up TERM request and terminate the environment
***-------------------------------------------------------------
DO_TERM  DS    0H
         MVC   P_RQ,TERM           set up TERM request
         SR    R1,R1               mark no parameters
         ST    R1,EP_PGPA
         LA    R1,PALIPT           set parameter pointer
         L     R15,CEP             set entry point
         BALR  R14,R15             invoke termination
***-------------------------------------------------------------
***      Return to system
***-------------------------------------------------------------
XIT      DS    0H
         L     R13,4(13)
         LM    R14,R12,12(13)
         BR    R14
***-------------------------------------------------------------
***      Constants and work areas
***-------------------------------------------------------------
VARCON   DS    0D
PALIPT   DC    A(X'80000000'+PALI)  Address of Parameter list
CEP      DC    A(CEESTART)          Entry point address
***-------------------------------------------------------------
PALI     DS    0F                   Parameter list
P_LG     DC    H'16'                Length of the list
         DC    H'0'                 Must be zero
P_RQ     DC    CL8' '               Request - INIT,CALL,TERM,EXECUTE
P_EP_PT  DC    A(EPALI)             Address of extended plist
***-------------------------------------------------------------
EPALI    DS    0F                   Extended Parameter list
         DC    A(EP_LG)             Length of this list
EP_TCA   DC    A(0)                 First token
EP_PRV   DC    A(0)                 Second token
EP_PGPA  DC    A(PGPAPT)            Address of C program plist
EP_XOPT  DC    A(XOPTPT)            Address of runtime options
EP_LG    EQU   *-EPALI              Length of this list
***-------------------------------------------------------------
***     C program plist in argc, argv format
***-------------------------------------------------------------
PGPAPT   DC    F'3'                  Number of parameters (argc)
         DC    A(PGVTPT)             parameter vector pter (argv)
PGVTPT   DS    0A                    Parameter Vector
         DC    A(PGNM)               Program name pointer (argv1)
         DC    A(FILE_NAME)          File name pointer    (argv2)
         DC    A(RUN_INDEX)          Run index pointer    (argv3)
         DC    XL4'00000000'         NULL pointer
***-------------------------------------------------------------
***     Runtime options
***-------------------------------------------------------------
XOPTPT   DC    A(X'80000000'+XOPTLG) Runtime options pter
XOPTLG   DC    AL2(XOPTSQ)           Runtime option list length
XOPTS    DC    C'STACK(4K) RPTSTG(ON)'   Runtime options list
XOPTSQ   EQU   *-XOPTS               Runtime options length
***-------------------------------------------------------------
PGNM       DC    C'CCNGCA7',X'00'       C program name
FILE_NAME  DC    C'PREINIT.DATA',X'00'   File name for C program
RUN_INDEX  DC    F'5',X'00'              changed by C Program
***-------------------------------------------------------------
***      Request strings for preinitialization
***-------------------------------------------------------------
INIT     DC    CL8'INIT'
CALL     DC    CL8'CALL'
TERM     DC    CL8'TERM'
EXEC     DC    CL8'EXECUTE'
***-------------------------------------------------------------
***      Assembler program's register save area
***-------------------------------------------------------------
SVAR     DC    18F'0'
         LTORG
***-------------------------------------------------------------
***      Register definitions
***-------------------------------------------------------------
R0       EQU   0
R1       EQU   1
R2       EQU   2
R3       EQU   3
R4       EQU   4
R5       EQU   5
R6       EQU   6
R7       EQU   7
R8       EQU   8
R9       EQU   9
R10      EQU   10
R11      EQU   11
R12      EQU   12
R13      EQU   13
R14      EQU   14
R15      EQU   15
         END

Program CCNGCA7 (Figure 2) shows how to use the preinitializable program.

Figure 2. Using the preinitializable program (CCNGCA7)
/* this example shows how to use a preinitializable program */
/* part 2 of 3 (other files are CCNGCA6 and CCNGCA8) */

#pragma runopts(PLIST(MVS))

#include <stdio.h>
#include <stdlib.h>

#define MAX_MSG 50
#define MAX_FNAME 8

typedef int (*f_ptr)(int, char*);/* pointer to function returning int*/

int main(int argc, char **argv)
{
  FILE *fp;                /* File to be written to */
  int *ptr_run;            /* Pointer to the "run index" */
  char *ffmsg;             /* a pointer to the "fetched function msg"*/
  char fname[MAX_FNAME+1]; /* name of the function to be fetched */
  int fetch_rc;            /* Return value of function invocation */
  f_ptr fetch_ptr;         /* Function pointer to fetched function */

  /* Get the pointer to the "run index" */
  ptr_run = (int *)argv[2];

  if ((fp = fopen(argv[1],"a")) == NULL)
   {
     printf("Cannot open file %s\n",argv[1]);
     *ptr_run = 0;         /* Set to zero so it won't be called again */
     return(0);            /* Return to Assembler program */
   }
  /* Write the record to the file */
  fprintf(fp,"Run index was %d.\n",*ptr_run);

  /* Allocate the message returned from the fetched function */
  if (( ffmsg=(char *)malloc(MAX_MSG + 1)) == NULL )
    printf("ERROR -- malloc returned NULL\n");

  /* fetch the function */
  fetch_ptr = (f_ptr) fetch("MYFUNC");
  if (fetch_ptr == NULL)
    printf("ERROR - Fetch returned a null pointer\n");

  /* execute the function */
  fetch_rc = fetch_ptr(*ptr_run, ffmsg);  /* Write the function msg to file */
  fprintf(fp,"%s\n",ffmsg);

  /* Tell the user the value of the "run index" */
  printf("Run index was %d.\n",*ptr_run);

  /* Decrement the "run index" */
  (*ptr_run)--;

  /* Remember to close all opened files */
  fclose(fp);

  /* Remember to free all allocated storage */
  free( fname );

  /* Remember to release all fetched modules */
  release((void(*)())fetch_ptr);

  /* Return to Assembler program */
  return(0);
}

Finally, Figure 3 shows sample program CCNGCA8.

Figure 3. Using the preinitializable program (CCNGCA8)
/* this example shows how to use a preinitializable program */
/* part 3 of 3 (other files are CCNGCA6 & CCNGCA7) */

#include <string.h>

#pragma  linkage(fetched, fetchable)

int fetched(int run_index, char *ffmsg) {
  sprintf(ffmsg,"Welcome to myfunc: Run index was %d.",run_index);
  return(0);
}