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.
/*
* 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;
}
/* 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);
}