APPENDIX B -- DEMONSTRATION PROGRAMS

Appendix B.1 contains a demonstration program, DEMOPGM, which uses the functions in the variable and parameter manipulation package.

Appendix B.2 contains a demonstration program to show use of dynamic q_ functions.

Appendix B.3 contains a demonstration program for an ASYNC-PROCESS.

B.1 DEMOPGM

/*
 *     demopgm - this program will demonstrate the use of the
 *     functions in the variable and parameter manipulation package.
 *
 *
 *     The PDF for this program is:
 *
 *             process
 *
 *             parm DATE type=INTEGER count=1:3 default=(1, 11, 18) +
 *                       valid=(1:31)
 *             parm COST type=REAL count=1:3 default=(12.5, 4.3, 36.9)
 *             parm NAME type=(STRING, 24) count=1:3 +
 *                       default=(GASOLINE, FRAME, GROCERY)
 *
 *             end-proc
 *
 */

#include     "taeconf.inp"
#include     "parblk.inc"
#include     <stdio>

FUNCTION main()


{
struct PARBLK      vblock;
CODE               status;
TEXT               file [FSPECSIZ+1];
FILE               *fp, *z_init(); /* structs for UNIX file output */
struct VARIABLE    *p_find();
struct VARIABLE    *date, *cost, *name;
TAEINT             vdate[] = 5;
TAEFLOAT           vcost[] = 16.75;
TEXT              *vname[] = "MAGTAPE";

                                           /* initialize for write to standard
                                           output and receive V-block from TM */
fp = z_init(&vblock, P_ABORT);
                                           /* get variables from V-block:     */
date = p_find (&vblock, "DATE");
cost = p_find (&vblock, "COST");
name = p_find (&vblock, "NAME");
                                           /* Check counts of each parameter: */
fprintf (fp, "\nC demo is running.\n"); 
if ((*date).v_count != 1)
    fprintf (fp, "DATE may have only one value.\n"); 
if ((*cost).v count != 1)
    fprintf (fp, "COST may have only one value.\n"); 
if ((*name).v_count != 1)
    fprintf (fp, "NAME may have only one value.\n");

                                           /* display the values:

fprintf (fp, "\n\t%s\tpurchased on : March %u\tfor: $%6.2f", 
                 SVAL(*name,O), IVAL(*date,O), RVAL(*cost,O));

                                           /* do some dynamic parameters      */

q_init (&vblock, P_BYTES, P ABORT);
q_dynp (&vblock, "", M_FULLPDF);           /* tutor on original PDF           */
p_inim (&vblock, sizeof(vblock), P_ABORT); /* receive the V-block from TM     */

                                           /* get variables from V-block      */
date = p_find (&vblock, "DATE"); 
cost = p_find (&vblock, "COST");
name = p_find (&vblock, "NAME");

                                         /* Check counts of each parameter:   */
if ((*date).v count != 1)
    fprintf (fp, "DATE may have only one value.\n");
if ((*cost).v count != 1)
    fprintf (fp, "COST may have only one value.\n");
if ((*name).v_count != 1)
    fprintf (fp, "NAME may have only one value.\n");

                                         /* display the values:               */

fprintf(fp, "\n\t%s\tpurchased on : March %u\tfor :  $%6.2f
                 SVAL(*name,O), IVAL(*date,0), RVAL(*cost,O));

                                         /* reconstruct the V-block:          */
q_intg(&vblock, "DATE", 1, vdate, P_UPDATE);
q_real(&vblock, "COST", 1, vcost, P_UPDATE);
q_string(&vblock, "NAME", 1, vname, P UPDATE);

                                         /* write V-block out on disk:        */
q_wrtb("demoblk.sav", 1, &vblock);

                                         /* read V-block from disk            */
                                         /* set mode to continue after failure*/
p_rdb("demoblk.sav", 1, &vblock, sizeof(vblock), P_CONT);

                                         /* get variables from V-block        */
date = p_find (&vblock, "DATE"); 
cost = p_find (&vblock, "COST"); 
name = p_find (&vblock, "NAME");

                                         /* Check counts of each parameter    */

if ((*date).v_count != 1)
    fprintf (fp, "DATE may have only one value.\n");
if ((*cost).v_count != 1)
    fprintf (fp, "COST may have only one value.\n");
if ((*name).v count != 1)
    fprintf (fp, "NAME may have only one value.\n");

                                         /* display the values                */

fprintf(fp, "\n\t%s\tpurchased on : March %u\tfor : $%6.2f", 
                 SVAL(*name,0), IVAL(*date,O), RVAL(*cost,O));

                                         /* set mode in V-block to abort      */
vblock.mode = P_ABORT;
                                         /* exit with success                 */
z_exit(1, "demo-success");
return;
}

B.2 DYNAMIC q_ FUNCTIONS

/*  Example program to show use of dynamic q functions.

 *  This program initializes a PARBLK structure, then
 *  adds variables to it. Using the new functions, it 
 *  sets valids and minimum and maximum counts for
 *  those variables. The PARELK is then saved to disk
 *  in a PAR file.
 *  The result of running this program is the file
 *  EXAMQ.PAR.
 *
 */

#include     <stdio.h>:
#include     "taeconf.inp"
#include     "parblk.inc"
#include     "terminc.inc"

FUNCTION main( )
{
struct PARELK     parblk;
FILE              *taeout, *z_init();
struct PARBLK     p;
FUNINT            dummy;


/*  Initialize TAE and get parblk (not used here)     */
    taeout = z_init( &parblk, P_ABORT );


/*  Initialize PARBLK structure.                       */
    q_init( &p, P_BYTES, P_ABORT );


/*  Add the variables A, B and S to the PARBLK.        */
/*  Use the new q_ functions to set valids and count.  */


/*     Define arrays for declaring integer variable    */
/*     with characteristics:                           */
/*     NAME=A TYPE=INTEGER COUNT=O: 4 +
/*     INITIAL(2,4,13) VALID=(1:l0, 20:30)             */

       TEXT            *iname = "A";
       FUNINT          imincount = 0, imaxcount = 4;
       TAEINT          ivalues[] = { 2, 4, 13 };
       FUNINT          nivalues = 3;
       TAEINT          ilow[] = { 1, 20 };
       TAEINT          ihigh[] = ( 10, 30 );
       FUNINT          nivalid = 2;

/*  Add variable A to the PARBLK.                      */
    q_intg(      &p, iname, nivalues, ivalues, P_ADD );
    q_validintg (&p, iname, nivalid, ilow, ihigh );
    q_min(       &p, iname, imincount );
    q_max(       &p, iname, imaxcount );


/*     Define arrays for declaring real variable       */
/*     with characteristics:                           */
/*     NAME=B TYPE=REAL COUNT=1 +                      */
       INITIAL=2.71 VALID=(0.1:1O.1, 20.5:30.0)         */

       TEXT            *rname    = "B";
       FUNINT          rmincount = 1, rmaxcount = 1;
       TAEFLOAT        rvalues[] = { 2.71 };
       FUNINT          nrvalues  = 1;
       TAEINT          rlow[]    = { 0.1, 20.5 };
       TAEINT          rhigh[]   = { 10.1, 30.0 };
       FUNINT          nrvalid   = 2;

/*     Add variable B to the PARBLK.
       q_real(      &p, rname, nrvalues, rvalues, P_ADD );
       q_validreal( &p, rname, nrvalid, rlow, rhigh );
       q_min(       &p, rname, rmincount );
       q_max        &p, rname, rmaxcount );


/*     Define arrays for declaring string variable     */
/*     with characteristics:                           */
/*     NAME=S TYPE=(STRING,5) COUNT=1:4 +              */
/*     INITIAL=("F", "T") VALID=("F", "T", "Y", "N")   */

       TEXT          *sname = "S"
       FUNINT        smincount = 1, smaxcount = 4;
       TEXT          *svalues[] = { "F", "T" };
       FUNINT        nsvalues = 2;
       TEXT          *svalids[] = { "F", "T", "Y", "N" };
       FUNINT        nsvalid = 4;

/*     Add variable S to the PARBLK.                   */

q_string(   &p sname, nsvalues, svalues, P_ADD );
q_validstr( &p sname, nsvalid, svalids );
q_min(      &p sname, smincount);
q_max(      &p sname, smaxcount);


/*  Write the PARBLK structure to disk (PAR file).      */

    qwrtb( "EXAMQ.PAR", dummy, &p );

/*  Terminate the program.                              */

    z_exit( 1, "Normal termination." );
}


B.3 SIMPLE C SERVER

/*     Demonstration program for ASYNC-PROCESS
 *
 *     This is a simple server that receives an integer TCL variable
 *     named "I", adds 1 to the value, and returns the value to
 *     the requesting job.
 */

#include     "TAECONF"          /* TAE standard defs     */
#include     "PARELK"           /* VBLOCK definitions    */
#include     "COMMINC"          /* PATH struct definition*/
#include     <stdio>            /* UNIX-like standard I/O*/

static FILE     *sysout = NULL;
static COUNT    get_string();
static TAEINT   get_integer();
static CODE     send_parblk();
struct VARIABLE *p_find();

VOID    terminate(); 
CODE    emit(); 
#define TERM    0xl000 
#define STATUS  0xl00l


main ()

{
struct PATH in_path;                              /* input path control block */
struct VARIABLE *v;
struct PARBLK in_parblk, out_parblk;              /* VBLOCKs                  */
CODE        code;
COUNT       i, l, parblk_size;
TEXT        *s;
TEXT        sender_job[STRINGSIZ+1],
            This_job [STRINGSIZ+1],
            Parent_job [STRINGSIZ+1];
TEXT        errmsg[STRINGSIZ+1];
COUNT       mb_size;                              /* size of mailbox to create*/
FILE        *z_init ();
COUNT       messages = 0;                         /* number processed         */
TAEINT      ivalue, ivv[1];                       /* integer value vector     */

sysout = z_init (&in_parblk, P_CONT);             /* get initial parameters   */
if (sysout == NULL)
    terminate (in_parblk.hostcode, "z_init failure");
emit (0, "alive");
get_string (&in_parblk, "CHILD", this job); 
get_string (&in_parblk, "PARENT", parent job);
fprintf (sysout, "Job '%s' under parent '%s'.\n", this_job, parent_job); 
mb_size = get integer (&in_parblk, "MB_SIZE");
code = c_crepath (&in_path, mb_size, this_job, TMPMBX); 
if (code != SUCCESS)
    {
    fprintf (sysout, "Cannot create input mailbox. %s\n", in_path.errmsg);
    terminate (in_path.host_code, "c_crepath error");
    }
q_init (&out_parblk, sizeof(out_parblk), P_CONT); 
send_parblk (&out_parblk, this_job, parent_job);  /* announce ready           */
messages = 0; 
while (FOREVER)
    {
    parblk size = mb_size; 
    code = c_getmsg (&in_path, (GENPTR)&in_parblk, &parblk size);
    makeabs (&in_parblk.symtab, in_parblk.pool); /* make ptrs absolute        */
    in_parblk.mode = P_CONT;                     /* continue on errors        */
    get_string(&in_parblk, " JOB", sender job); 
    q_init (&out_parblk, P_BYTES, P_CONT); 
    ivalue = get_integer (&in_parblk, "I");      /* get TCL variable          */
    ivalue++;
    ivv[0] = ivalue;
    q_intg (&out_parblk, "I", I, ivv, P_ADD);    /* put I in parblk           */
    send_parblk (&out_parblk, this_job, sender_job);
    messages++; 
    emit (messages, "running");                  /* announce new status       */
    }
}


FUNCTION static TAEINT get_integer (parblk, name)

struct PARBLK *parblk;        /* in: VBLOCK                                   */
TEXT          name [];        /* in: name of variable                         */

{
struct VARIABLE *v;

v = p_find (parblk, name); 
if (v == NULL)
    {
    fprintf (sysout, "Cannot find variable '%s'.", name);
    terminate (-1, "No variable.");
    }
return (IVAL(*v,0));
}


FUNCTION static COUNT get_string (parblk, name, output)

struct PARBLK *parblk;         /* in: VBLOCK                                  */
TEXT          name[];          /* in: name of variable                        */
TEXT        output[];          /* out: string value                           */

{
struct VARIABLE *v;

v = p_find (parblk, name); 
if (v == NULL)
    {
    fprintf (sysout, "Cannot find variable '%s'.", name);
    terminate (-1, "No variable.");
    }
return (s_copy (SVAL(*v,O), output));     /* return string length             */
}


FUNCTION static CODE send_parblk (parblk, this_job, target_job)

struct PARBLK      *parblk;          /* in: parblk to send                    */
TEXT               this_job[];       /* in: name of current job               */
TEXT               target job[];     /* in: name of job to send it to         */

{
IMPORT GENPTR      r_top();          /* current top of allocated area         */ 
TEXT               *valvec [1];      /* string value vector for _JOB          */
TEXT               errmsg[STRINGSIZ+1];
CODE               code;

valvec[O] = this_job;
q_string (parblk, "JOB", 1, valvec, P_ADD);   /* tell target who we are       */ 
(*parblk).blksiz = r_top ((*parblk).pool) - (GENPTR)parblk; 
makerel (&(*parblk).symtab, (*parblk).pool);. /* make ptrs relative           */
code = c_pmwcd (target_job, (GENPTR)parblk, (*parblk).blksiz, errmsg); 
if (code != SUCCESS)
    fprintf (sysout, "Cannot send to '%s'. %s.\n", target job, errmsg); 
return (code); .
}


/*     emit. Emit status to parent. This is process analogy of 
 *     the TCL EMIT command.
 *
 *     Currently, under UNIX, there
 *     appears to be a bug whereby back-to-back emits
 *     causes one or both of the emits to be lost.
 */

#include     "ASYNCINC"

    FUNCTION CODE emit (sfi, skey)

    FUNINT      sfi;          /* in: $SFI to report                           */
    TEXT     skey[];          /* in: SSKEY to report                          */

    {
    struct MON_MSG     msg;
    CODE             code;

    msg.type = MO_STATUS;
    msg.m_sfi = sfi;
    s_bcopy (skey, msg.m_skey, sizeof(msg.m_skey) - 1);
    code = c_snpa ((GENPTR)&msg, sizeof (msg)); 
    return (code);
    }



    FUNCTION VOID terminate (sfi, skey)

    FUNINT        sfi;            /* in: final $SFI status                    */
    TEXT      skey[];            /* in: final $SKEY string                    */

    {
    struct MON_MSG msg;

#ifndef UNIX                  /* avoid back-to-back messages                  */
    emit (sfi, skey);         /* emit final status                            */
#endif
    msg.type = MO_TERM;       /* tell parent we're terminating                */
    c_snpa ((GENPTR)&msg, sizeof(msg));
    exit (1);
    }