Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Rexx / how to write a function in C / C++ [Virus checked]

15 views
Skip to first unread message

Ralph Bremer

unread,
Aug 26, 2004, 12:18:20 PM8/26/04
to
Hello,

i wold like to write a rexx function in C ( or C++ ??? )
i wold need to parse the arguments,
access rexx-variables
and return a result ....
the function should be usable simply by being in STEPLIB ....

unfortunately i cant find any sample how to write a REXX Function in C ...
( and how to access the variables / the netview environment from the
function )

anyone out there has a sample ??

Ralph Bremer

----------------------------------------------------------------------
For TSO-REXX subscribe / signoff / archive access instructions,
send email to LIST...@VM.MARIST.EDU with the message: INFO TSO-REXX

Stephen E. Bacher

unread,
Aug 26, 2004, 12:28:26 PM8/26/04
to
Ralph Bremer wrote:

>i wold like to write a rexx function in C ( or C++ ??? )
>i wold need to parse the arguments,
>access rexx-variables
>and return a result ....
>the function should be usable simply by being in STEPLIB ....
>
>unfortunately i cant find any sample how to write a REXX Function in C ...
>( and how to access the variables / the netview environment from the
>function )
>
>anyone out there has a sample ??

As a matter of fact, I do. (And I was the one who posted
last week that you couldn't do it. :-)

Here is a C program used by the MVS Gopher server for invocation
from server-side REXX execs.

I believe the "edcxregs" routine is part of the IBM C runtime.

Hope this helps.

Steve Bacher
Draper Laboratory
s...@draper.com

--- cut here ---

/********************************************************************/
/* */
/* Copyright (c) The Charles Stark Draper Laboratory, 1992, 1993 */
/* */
/* This software is provided on an "AS IS" basis. All warranties, */
/* including the implied warranties of merchantability and fitness, */
/* are expressly denied. */
/* */
/* Provided this copyright notice is included, this software may */
/* be freely distributed and not offered for sale. */
/* */
/* Changes or modifications may be made and used only by the maker */
/* of same, and not further distributed. Such modifications should */
/* be mailed to the author for consideration for addition to the */
/* software and incorporation in subsequent releases. */
/* */
/********************************************************************/

/*
***********************************************************************
* *
* This is not a main program, nor a subroutine to be linked into an *
* existing program, but a routine which is to be called from a *
* REXX exec as follows: *
* *
* dsn = "name.of.data.set" -- or null to create a temporary *
* dnn = "ddname" -- or null to generate a unique one *
* disp = "SHR" -- or "OLD", "NEW", "FREE" or "DELETE" *
* msg1 = "" -- to be set with an error message *
* msg2 = "" -- to be set with an error message *
* *
* address LINKMVS "XGALLOC DSN DDN DISP MSG1 MSG2" *
* *
* In addition to possibly updating the indicated variables, this *
* routine returns a return code, which becomes the value of "RC". *
* *
* The purpose of this routine is to provide a way for REXX execs *
* to perform allocation and unallocation of data sets from a non-TSO *
* environment. The LINKMVS (or ATTCHMVS) interface allows it to *
* update the specified REXX variables by setting values for the *
* passed parameters without calling REXX routines directly. *
* *
* Use of this routine requires TSO/REXX 3.46 or higher. *
* *
***********************************************************************
*/

#pragma environment(XGALLOC)
#pragma linkage(ikjeff18,OS)

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

/* #define FETCH */
#undef FETCH

#define Bool char
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif

#define S99VRBAL 0x01 /* ALLOCATION */
#define S99VRBUN 0x02 /* UNALLOCATION */
#define S99VRBCC 0x03 /* CONCATENATION */
#define S99VRBDC 0x04 /* DECONCATENATION */
#define S99VRBRI 0x05 /* REMOVE IN-USE */
#define S99VRBDN 0x06 /* DDNAME ALLOCATION */
#define S99VRBIN 0x07 /* INFORMATION RETRIEVAL */
#define S99NOCNV 0x40 /* ALLOC FUNCTION-DO NOT USE AN */
/* EXISTING ALLOCATION TO SATISFY*/
/* THE REQUEST */
#define DALDDNAM 0x0001 /* DDNAME */
#define DALDSNAM 0x0002 /* DSNAME */
#define DALMEMBR 0x0003 /* MEMBER NAME */
#define DALSTATS 0x0004 /* DATA SET STATUS */
#define DALNDISP 0x0005 /* DATA SET DISPOSITION */
#define DALTRK 0x0007 /* TRACK SPACE TYPE */
#define DALBLKLN 0x0009 /* BLOCK LENGTH */
#define DALPRIME 0x000a /* PRIMARY SPACE ALLOCATION */
#define DALSECND 0x000b /* SECONDARY SPACE ALLOCATION */
#define DALDIR 0x000c /* DIRECTORY BLOCK ALLOCATION */
#define DALSYSOU 0x0018 /* SYSOUT */
#define DALSFMNO 0x001a /* SYSOUT FORMS NUMBER */
#define DALCOPYS 0x001d /* SYSOUT COPIES */
#define DALUCS 0x0029 /* UNIVERSAL CHARACTER SET */
#define DALBLKSZ 0x0030 /* DCB BLOCKSIZE */
#define DALDSORG 0x003c /* DATA SET ORGANIZATION */
#define DALLRECL 0x0042 /* DCB LOGICAL RECORD LENGTH */
#define DALRECFM 0x0049 /* DCB RECORD FORMAT */
#define DALPERMA 0x0052 /* PERMANENTLY ALLOCATED ATTRIB */
#define DALRTDDN 0x0055 /* RETURN DDNAME */
#define DALRTDSN 0x0056 /* RETURN DSNAME */
#define DALRTORG 0x0057 /* RETURN D.S. ORGANIZATION */
#define DALSUSER 0x0058 /* SYSOUT REMOTE WORKSTATION */
#define DUNDDNAM 0x0001 /* DDNAME */
#define DUNDSNAM 0x0002 /* DSNAME */
#define DUNUNALC 0x0007 /* UNALLOC OPTION */
#define SHR 0x08
#define NEW 0x04
#define MOD 0x02
#define OLD 0x01
#define KEEP 0x08
#define DELETE 0x04
#define CATLG 0x02
#define UNCATLG 0x01
#define RECFM_F 0x80
#define RECFM_V 0x40
#define RECFM_U 0xc0
#define RECFM_D 0x20
#define RECFM_T 0x20
#define RECFM_B 0x10
#define RECFM_S 0x08
#define RECFM_A 0x04
#define RECFM_M 0x02
#define RECFM_FB (RECFM_F | RECFM_B)
#define RECFM_VB (RECFM_V | RECFM_B)
#define DSORG_PS 0x4000
#define DSORG_PO 0x0200

enum disposition {DISP_SHR,DISP_OLD,DISP_MOD,
DISP_NEW,DISP_KEEP,DISP_DELETE};

#define uppercase_in_place(C) {char *__cp;\
for(__cp=C;*__cp;__cp++) *__cp = toupper(*__cp);}

#define copy_uppercase(A,B) {char *__cA,*__cB;\
for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
*__cA = toupper(*__cB);\
*__cA='\0';}

#define set2(A,B) *(short *)(A) = B
#define set3(A,B) memset(A,0,3); *(short *)(A+1) = B

struct _textunit {
unsigned short key;
unsigned short num;
struct {
unsigned short len;
char prm[80];
} ent;
};

struct varstring {
short len;
char text[1];
};

typedef struct _textunit TEXTUNIT;
typedef struct varstring VARSTRING;

/*--------------------------------------------------------------------*/

static void
allocfail(rc,p99,msg1,msg2)
int rc;
__S99parms *p99;
char *msg1;
char *msg2;
{
int zero = 0;
unsigned int dfid = 0x40320000;
struct {
short first_level_msg_len;
short first_level_msg_offset;
char first_level_msg[251];
short second_level_msg_len;
short second_level_msg_offset;
char second_level_msg[251];
} dfbuffer;

static int (*ikjeff18_pointer)() = NULL;

#ifndef FETCH
extern int *ikjeff18();
#endif

strcpy(msg1,"");
strcpy(msg2,"");

if (!ikjeff18_pointer) {
#ifdef FETCH
ikjeff18_pointer = (int (*)())fetch("IKJEFF18");
#else
ikjeff18_pointer = (int (*)())ikjeff18;
#endif
}

dfbuffer.first_level_msg_len = 4;
dfbuffer.second_level_msg_len = 4;

if (ikjeff18_pointer) {
if ((*ikjeff18_pointer)(p99,&rc,&zero,&dfid,&zero,&dfbuffer)) {
strcpy(msg1,"IKJEFF18 returned a nonzero return code");
}
if (dfbuffer.first_level_msg_len > 0) {
strncpy(msg1, dfbuffer.first_level_msg,
dfbuffer.first_level_msg_len-4);
}
if (dfbuffer.second_level_msg_len > 0) {
strncpy(msg2, dfbuffer.second_level_msg,
dfbuffer.second_level_msg_len-4);
}
}
else {
#ifdef FETCH
strcpy(msg1,"xgalloc cannot fetch IKJEFF18");
#else
strcpy(msg1,"IKJEFF18 was not linked with xgalloc");
#endif
}
return;
}

/*--------------------------------------------------------------------*/

static void
setmsg(msgvar,string)
VARSTRING *msgvar;
char *string;
{

msgvar->len = strlen(string);
memcpy(msgvar->text,string,msgvar->len);
return;
}

/*--------------------------------------------------------------------*/

int
XGALLOC()
{
VARSTRING **reg1;
VARSTRING *dsnvar;
VARSTRING *ddnvar;
VARSTRING *dispvar;
VARSTRING *msg1var;
VARSTRING *msg2var;
int i;
int rc;
int disp99_1;
int disp99_2;
Bool unal;
enum disposition disp;
short primary_allocation = 0;
short secondary_allocation = 0;
short directory_blocks = 0;
short dsorg = 0;
char recfm = 0;
short lrecl = 0;
short blocksize = 0;
__S99parms stuff99; /* No "struct", despite manual */
TEXTUNIT *return_dsname_tup = NULL;
TEXTUNIT *return_ddname_tup = NULL;
TEXTUNIT *tup [32];
TEXTUNIT tu [32];
char *lparp;
char *rparp;
char dsname [81];
char ddname [9];
char dispname [9];
char member [81];
char msg1 [256];
char msg2 [256];

reg1 = (VARSTRING **)edcxregs(1);

dsnvar = reg1[0];
ddnvar = reg1[1];
dispvar = reg1[2];
msg1var = reg1[3];
msg2var = reg1[4];

memset((char *)&stuff99,0,sizeof(__S99parms));
strcpy(msg1,"");
strcpy(msg2,"");

if (dsnvar->len > 56) {
setmsg(msg1var,"DSNAME argument cannot be longer than 56");
return 16;
}
if (ddnvar->len > 8) {
setmsg(msg1var,"DDNAME argument cannot be longer than 8");
return 16;
}
if (dispvar->len > 8) {
setmsg(msg1var,"DISP must be SHR/OLD/MOD/NEW/FREE/KEEP/DELETE");
return 16;
}

strncpy(dsname,dsnvar->text,dsnvar->len);
strncpy(ddname,ddnvar->text,ddnvar->len);
strncpy(dispname,dispvar->text,dispvar->len);
uppercase_in_place(dsname);
uppercase_in_place(ddname);
uppercase_in_place(dispname);

if (!strcmp(dispname,"SHR")) disp = DISP_SHR;
else if (!strcmp(dispname,"OLD")) disp = DISP_OLD;
else if (!strcmp(dispname,"MOD")) disp = DISP_MOD;
else if (!strcmp(dispname,"NEW")) disp = DISP_NEW;
else if (!strcmp(dispname,"FREE")) disp = DISP_KEEP;
else if (!strcmp(dispname,"KEEP")) disp = DISP_KEEP;
else if (!strcmp(dispname,"DELETE")) disp = DISP_DELETE;
else {
setmsg(msg1var,"DISP must be SHR/OLD/MOD/NEW/FREE/KEEP/DELETE");
return 16;
}

switch (disp) {
case DISP_SHR: unal=FALSE; disp99_1=SHR; disp99_2=KEEP; break;
case DISP_OLD: unal=FALSE; disp99_1=OLD; disp99_2=KEEP; break;
case DISP_MOD: unal=FALSE; disp99_1=MOD; disp99_2=CATLG; break;
case DISP_NEW: unal=FALSE; disp99_1=NEW; disp99_2=CATLG; break;
case DISP_KEEP: unal=TRUE; disp99_2=KEEP; break;
case DISP_DELETE: unal=TRUE; disp99_2=DELETE; break;
}

switch (disp) {
case DISP_MOD:
case DISP_NEW:
primary_allocation = 100;
secondary_allocation = primary_allocation;
dsorg = DSORG_PS;
recfm = RECFM_VB;
lrecl = 256;
blocksize = 23440;
break;
}

strcpy(member,"");
lparp = strchr(dsname,'(');
rparp = strchr(dsname,')');
if (lparp && rparp && (lparp < rparp) && (*(rparp+1) == '\0')) {
*lparp = '\0'; /* makes dsname the seq part only */
*rparp = '\0'; /* turns member into a string */
strcpy(member, lparp+1);
}

stuff99.__S99RBLN = 20;
stuff99.__S99VERB = unal ? S99VRBUN : S99VRBAL;
stuff99.__S99FLAG1 = S99NOCNV << 8;
stuff99.__S99ERROR = 0;
stuff99.__S99INFO = 0;
stuff99.__S99TXTPP = tup;
stuff99.__S99FLAG2 = 0;

for (i=0; i<32; i++) tup[i] = &tu[i];

i = 0;

if (*dsname) {
tu[i].key = unal ? DUNDSNAM : DALDSNAM;
tu[i].num = 1;
tu[i].ent.len = strlen(dsname);
copy_uppercase(tu[i].ent.prm,dsname);
i++;
}
else if (!unal) {
tu[i].key = DALRTDSN;
tu[i].num = 1;
tu[i].ent.len = 44;
memset(tu[i].ent.prm,' ',44);
return_dsname_tup = &tu[i];
i++;
}
if (*member) {
tu[i].key = DALMEMBR;
tu[i].num = 1;
tu[i].ent.len = strlen(member);
copy_uppercase(tu[i].ent.prm,member);
i++;
}
if (*ddname) {
tu[i].key = unal ? DUNDDNAM : DALDDNAM;
tu[i].num = 1;
tu[i].ent.len = strlen(ddname);
copy_uppercase(tu[i].ent.prm,ddname);
i++;
if (!unal) {
tu[i].key = DALPERMA;
tu[i].num = 0;
i++;
}
}
else if (!unal) {
tu[i].key = DALRTDDN;
tu[i].num = 1;
tu[i].ent.len = 8;
memset(tu[i].ent.prm,' ',8);
return_ddname_tup = &tu[i];
i++;
}
if (unal) {
tu[i].key = DUNUNALC;
tu[i].num = 0;
i++;
}
else {
tu[i].key = DALSTATS;
tu[i].num = 1;
tu[i].ent.len = 1;
tu[i].ent.prm[0] = disp99_1;
i++;
tu[i].key = DALNDISP;
tu[i].num = 1;
tu[i].ent.len = 1;
tu[i].ent.prm[0] = disp99_2;
i++;
}
if (recfm) {
tu[i].key = DALRECFM;
tu[i].num = 1;
tu[i].ent.len = 1;
tu[i].ent.prm[0] = recfm;
i++;
}
if (lrecl) {
tu[i].key = DALLRECL;
tu[i].num = 1;
tu[i].ent.len = 2;
set2(tu[i].ent.prm,lrecl);
i++;
}
if (blocksize) {
tu[i].key = DALBLKSZ;
tu[i].num = 1;
tu[i].ent.len = 2;
set2(tu[i].ent.prm,blocksize);
i++;
}
if (blocksize) {
tu[i].key = DALBLKLN;
tu[i].num = 1;
tu[i].ent.len = 3;
set3(tu[i].ent.prm,blocksize);
i++;
}
if (primary_allocation) {
tu[i].key = DALPRIME;
tu[i].num = 1;
tu[i].ent.len = 3;
set3(tu[i].ent.prm,primary_allocation);
i++;
}
if (secondary_allocation) {
tu[i].key = DALSECND;
tu[i].num = 1;
tu[i].ent.len = 3;
set3(tu[i].ent.prm,secondary_allocation);
i++;
}
if (dsorg) {
tu[i].key = DALDSORG;
tu[i].num = 1;
tu[i].ent.len = 2;
set2(tu[i].ent.prm,dsorg);
i++;
}

tup[i] = (void *)0x80000000;

rc = svc99(&stuff99);

if (rc == 0) {
if (return_dsname_tup) {
memcpy(dsnvar->text,(char *)return_dsname_tup->ent.prm,64);
dsnvar->len = return_dsname_tup->ent.len;
}
if (return_ddname_tup) {
memcpy(ddnvar->text,(char *)return_ddname_tup->ent.prm,8);
ddnvar->len = return_ddname_tup->ent.len;
}
}
else {
allocfail(rc,&stuff99,msg1,msg2);
}
setmsg(msg1var,msg1);
setmsg(msg2var,msg2);
return rc;

0 new messages