RU/2: Форум. Общение пользователей и разработчиков OS/2 (eCS). : Writing REXX add-ons in C - Exsample Code (2002)


Список сообщений | Написать новое | Ответить на сообщение | Домой Поиск:
Предыдущее сообщение | Следующее сообщение
From : GA
To : All
Subj : Writing REXX add-ons in C - Exsample Code (2002)

/* Writing Rexx add-ons in C - example code copyright (C) Ian Collier 2002 */

/* This program code may be used for any purpose provided that
due acknowledgement is given. */

#define INCL_RXFUNC
#define INCL_RXSHV
#include <rexxsaa.h>
#define RXFUNC_ERROR 40

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

APIRET plus1_function(PSZ name, ULONG argc, RXSTRING argv[], PSZ queue, PRXSTRING answer) {
int x=-1;
if (argc>0 && RXVALIDSTRING(argv[0]))
sscanf(argv[0].strptr,"%d",&x);
x++;
sprintf(answer->strptr, "%d", x);
answer->strlength=strlen(answer->strptr);
return 0;
}

APIRET plus2_function(PSZ name, ULONG argc, RXSTRING argv[], PSZ queue, PRXSTRING answer) {
int x;
char dummy;
if (argc!=1 || !RXVALIDSTRING(argv[0]) ||
sscanf(argv[0].strptr," %d %c", &x, &dummy)!=1)
return RXFUNC_ERROR;
x+=2;
sprintf(answer->strptr, "%d", x);
answer->strlength=strlen(answer->strptr);
return 0;
}

/* This function checks that the supplied variable name is a valid
stem name. Returns 0 if not; otherwise it determines whether
the stem already has a value and returns 1 if the stem is valid
but without a value and 2 if it has a value. */
static int valid_variable(RXSTRING varname) {
SHVBLOCK shv;
int l=RXSTRLEN(varname); /* shortcuts for the length */
char *s=RXSTRPTR(varname); /* and string pointer */
static char buffer[10]; /* to hold a portion of the fetched value */
char *p;
int rcode;

/* null or empty name: invalid */
if (!RXVALIDSTRING(varname)) return 0;
/* invalid if name contains '0'x */
if (strlen(s) != l) return 0;
/* '.' must be the last and only the last character */
p=strchr(s,'.');
if (!p || p+1-s != l) return 0;
/* now try to fetch the stem name */
shv.shvnext=0;
shv.shvcode=RXSHV_SYFET;
shv.shvname=varname;
MAKERXSTRING(shv.shvvalue, buffer, 0);
shv.shvvaluelen=sizeof buffer;
rcode=RexxVariablePool(&shv);
/* any flag other than RXSHV_NEWV or RXSHV_TRUNC means the
request failed, so return a default of 0 */
if (rcode & ~(RXSHV_NEWV|RXSHV_TRUNC)) return 0;
/* return 1 if new, 2 if not. */
if (rcode & RXSHV_NEWV) return 1;
return 2;
}

/* This function compares two RXSTRINGs for use in the qsort function */
static int rxstring_compare(const void *s1, const void *s2) {
char *v1=RXSTRPTR(*(RXSTRING*)s1);
char *v2=RXSTRPTR(*(RXSTRING*)s2);
int l1=RXSTRLEN(*(RXSTRING*)s1);
int l2=RXSTRLEN(*(RXSTRING*)s2);
int minl = (l1<l2 ? l1 : l2);
int r=strncmp(v1, v2, minl);
if (r) return r;
return l1-l2;
}

APIRET sort_function(PSZ name, ULONG argc, RXSTRING argv[], PSZ queue, PRXSTRING answer) {
RXSTRING *elts=0;
int nelts;
SHVBLOCK shv;
char *var1, *var2;
int var1len, var2len;
static char vname[270];
static char vval[14];
int rcode;
char *v;
int l;
char c;
int i;

if (argc!=2 || !RXVALIDSTRING(argv[0]) || !RXVALIDSTRING(argv[1]))
return RXFUNC_ERROR; /* invalid syntax */

/* both arguments should be valid stems */
if (!valid_variable(argv[0]) || !valid_variable(argv[1]))
return RXFUNC_ERROR;
var1=RXSTRPTR(argv[0]);
var1len=RXSTRLEN(argv[0]);
var2=RXSTRPTR(argv[1]);
var2len=RXSTRLEN(argv[1]);

/* make sure the stem name and a numeric tail will fit into vname */
if (sizeof vname<var1len+14 || sizeof vname<var2len+14)
return RXFUNC_ERROR; /* name too long */

/* var1.0 must contain a numeric value of at most (say) 9 digits */
sprintf(vname, "%s0", var1);
shv.shvnext=0;
shv.shvcode=RXSHV_SYFET;
MAKERXSTRING(shv.shvname, vname, strlen(vname));
MAKERXSTRING(shv.shvvalue, vval, 0);
shv.shvvaluelen=sizeof vval;
rcode=RexxVariablePool(&shv);
if (rcode) return RXFUNC_ERROR; /* the fetch must return success */
v=RXSTRPTR(shv.shvvalue);
l=RXSTRLEN(shv.shvvalue);
if (l>9)
return RXFUNC_ERROR; /* value was too long to be a proper number */
v[l]=0;
rcode=sscanf(v, " %d %c", &nelts, &c);
if (rcode!=1)
return RXFUNC_ERROR; /* the value didn't decode into a number */
if (nelts<0)
return RXFUNC_ERROR; /* the value must be nonnegative */
if (nelts>0) {
elts=malloc(nelts*sizeof *elts);
if (!elts) return RXFUNC_ERROR; /* out of memory */
}

/* now collect each tail */
for (i=0; i<nelts; i++) {
sprintf(vname, "%s%d", var1, i+1);
MAKERXSTRING(shv.shvname, vname, strlen(vname));
MAKERXSTRING(shv.shvvalue, 0, 0);
shv.shvvaluelen=0;
rcode=RexxVariablePool(&shv);
if (RXNULLSTRING(shv.shvvalue)) break; /* leave on error */
elts[i]=shv.shvvalue;
}
nelts=i; /* this is how many elements were actually processed */

if (nelts>1) qsort(elts, nelts, sizeof *elts, rxstring_compare);

/* set var2.0 to the number of elements */
sprintf(vname, "%s0", var2);
sprintf(vval, "%d", nelts);
shv.shvcode=RXSHV_SYSET;
MAKERXSTRING(shv.shvname, vname, strlen(vname));
MAKERXSTRING(shv.shvvalue, vval, strlen(vval));
rcode |= RexxVariablePool(&shv);

/* Set the other elements of var2. to the sorted elements */
for (i=0; i<nelts; i++) {
sprintf(vname, "%s%d", var2, i+1);
MAKERXSTRING(shv.shvname, vname, strlen(vname));
shv.shvvalue=elts[i];
rcode |= RexxVariablePool(&shv);
free(RXSTRPTR(elts[i]));
}
if (elts) free(elts);

/* decide what to return */
answer->strlength=1;
i=0;
if (rcode & ~RXSHV_NEWV) i++; /* some kind of error: i=1 */
if (rcode & RXSHV_MEMFL) i++; /* out of memory: i=2 */
answer->strptr[0]='0'+i;
return 0;
}

APIRET keys_function(PSZ name, ULONG argc, RXSTRING argv[], PSZ queue, PRXSTRING answer) {
int maxkeys;
int nkeys=0;
RXSTRING *keys, *newkeys;
SHVBLOCK get, *put, *putp;
char *pad=" ";
static char buffer[10];
char *var1, *var2=0;
int var1len, var2len;
char *vname;
int padlen=1;
int totlen=0;
int stemset;
int rcode;
char *v;
int l;
int i;

if (argc<1 || argc>2 || !RXVALIDSTRING(argv[0]))
return RXFUNC_ERROR; /* invalid syntax */

/* first argument should be a valid stem */
stemset=valid_variable(argv[0]);
if (!stemset--) return RXFUNC_ERROR; /* invalid variable name */
/* stemset now says whether the stem was set */
var1=RXSTRPTR(argv[0]);
var1len=RXSTRLEN(argv[0]);

/* second argument if present is a stem if it ends with '.' and a
pad otherwise. */
if (argc==2) {
if (valid_variable(argv[1])) {
var2=RXSTRPTR(argv[1]); /* valid stem */
var2len=RXSTRLEN(argv[1]);
}
else if (!RXVALIDSTRING(argv[1]))
return RXFUNC_ERROR; /* empty string not allowed */
else {
pad=RXSTRPTR(argv[1]);
padlen=RXSTRLEN(argv[1]);
if (pad[padlen-1]=='.')
return RXFUNC_ERROR; /* it was a failed variable name */
}
}

/* begin collecting keys */
keys=malloc((maxkeys=256)*sizeof *keys);
if (!keys) return RXFUNC_ERROR; /* out of memory */
get.shvnext=0;
get.shvcode=RXSHV_NEXTV;
MAKERXSTRING(get.shvvalue, buffer, 0);
get.shvvaluelen=sizeof buffer;
while (1) {
MAKERXSTRING(get.shvname,0,0);
get.shvnamelen=0;
rcode=RexxVariablePool(&get);
if (rcode & ~RXSHV_TRUNC) break;
v=RXSTRPTR(get.shvname);
if (RXSTRLEN(get.shvname) >= var1len &&
strncasecmp(v, var1, var1len)==0)
{
/* we have initial match, so it's one of ours */
l=RXSTRLEN(get.shvname)-var1len;
if (!l) {
/* Variable has no tail. If the stem is set then assume
this is it and ignore it this once. */
if (stemset) {
stemset--;
free(v);
continue;
}
}
if (nkeys==maxkeys) { /* allocate some more memory */
newkeys=realloc(keys, (maxkeys*=2) * sizeof *keys);
if (!newkeys) { /* out of memory - break the loop */
rcode=RXSHV_MEMFL;
break;
}
keys=newkeys;
}
MAKERXSTRING(keys[nkeys], v+var1len, l);
if (nkeys++) totlen+=padlen;
totlen+=l;
} else {
/* not one of ours - free the memory */
free(v);
/* Assume that the tails of a stem are returned contiguously */
if (nkeys) break;
}
}
/* all the keys are collected, or else rcode contains an error code. */

if (nkeys>1) qsort(keys, nkeys, sizeof *keys, rxstring_compare);

/* Prepare to return a result. If var2 is null then the result is
just a single string with all the tails joined together. */
if (!var2) {
char *result;
if (totlen < RXSTRLEN(*answer))
result=RXSTRPTR(*answer); /* result fits in the supplied buffer */
else {
result=malloc(totlen);
if (!result) {
totlen=0;
result=RXSTRPTR(*answer);
rcode=RXSHV_MEMFL;
}
}
MAKERXSTRING(*answer, result, totlen);
for (i=0; i<nkeys; i++) {
if (totlen) { /* only copy string if there was memory */
if (i>0) { /* pad all except first key */
memcpy(result, pad, padlen);
result+=padlen;
}
memcpy(result, RXSTRPTR(keys[i]), RXSTRLEN(keys[i]));
result+=RXSTRLEN(keys[i]);
}
free(RXSTRPTR(keys[i])-var1len);
}
free(keys);
if (totlen==0 && (rcode & ~(RXSHV_LVAR|RXSHV_TRUNC))) {
/* no keys were collected and an error occurred */
return RXFUNC_ERROR;
}
return 0;
} else {
/* var2 is a stem which should be used to hold all the keys */
/* put is a big block of memory to hold all the requests and
also all the variables to set */
put=malloc((nkeys+1)*(sizeof *put + var2len+10)+10);
putp=put;
if (putp) { /* put "var2.0" which is the number of keys */
char *var2val=(char *)(keys+nkeys+1);
/* (first free character in the big block) */
int var2vallen;
sprintf(var2val, "%d", nkeys);
var2vallen=strlen(var2val);
MAKERXSTRING(putp->shvvalue, var2val, var2vallen);
vname=var2val+var2vallen;
sprintf(vname, "%s0", var2);
MAKERXSTRING(putp->shvname, vname, strlen(vname));
vname+=strlen(vname);
putp->shvcode=RXSHV_SYSET;
}
for (i=0; i<nkeys; i++) {
/* set each element of the stem var2 to a key */
if (putp) {
putp->shvnext = putp+1;
putp++;
sprintf(vname, "%s%d", var2, i+1);
MAKERXSTRING(putp->shvname, vname, strlen(vname));
vname+=strlen(vname);
putp->shvvalue = keys[i];
putp->shvcode=RXSHV_SYSET;
}
}
if (putp) {
/* this dumps all the above variables into Rexx */
putp->shvnext=0;
rcode |= RexxVariablePool(put);
free(put);
}
/* now all the memory can be freed */
for (i=0; i<nkeys; i++)
free(RXSTRPTR(keys[i])-var1len);
free (keys);

/* finally, decide what to return */
if (!putp)
return RXFUNC_ERROR; /* out of memory - couldn't set var2 */
if (nkeys==0 && (rcode & ~(RXSHV_LVAR|RXSHV_TRUNC))) {
/* no keys were collected and an error occurred */
return RXFUNC_ERROR;
}
/* Success (of some sort) so set the return value to
indicate how successful. */
answer->strlength=1;
i=0;
if (rcode & ~(RXSHV_LVAR|RXSHV_TRUNC))
i++; /* some kind of error: i=1 */
if (rcode & RXSHV_MEMFL)
i++; /* out of memory error: i=2 */
answer->strptr[0] = '0'+i;
return 0;
}
}

APIRET RegisterFunctions(PSZ name, ULONG argc, RXSTRING argv[], PSZ queue, PRXSTRING answer) {
int rcode=0;
char dllname[]=__FILE__;
char *p=strrchr(dllname,'.');
int r;
if (p) p[0]=0;
if (argc>0) return RXFUNC_ERROR;
rcode=RexxRegisterFunctionDll("PLUS1", dllname, "plus1_function");
r=RexxRegisterFunctionDll("PLUS2", dllname, "plus2_function");
if (r>rcode) rcode=r;
r=RexxRegisterFunctionDll("STEMSORT", dllname, "sort_function");
if (r>rcode) rcode=r;
r=RexxRegisterFunctionDll("STEMTAILS", dllname, "keys_function");
if (r>rcode) rcode=r;
sprintf(answer->strptr, "%d", rcode);
answer->strlength=strlen(answer->strptr);
return 0;
}

/* the following is an optional extra for REXX/imc - please ignore... */
struct {char *name; RexxFunctionHandler *function;} rxdictionary[]={
{"PLUS1",plus1_function},
{"PLUS2",plus2_function},
{"STEMSORT",sort_function},
{"STEMTAILS",keys_function},
{NULL,NULL}
};


Wed 22 Oct 2003 15:35 Mozilla/4.61 [en] (OS/2; U)




Programmed by Dmitri Maximovich, Dmitry I. Platonoff, Eugen Kuleshov.
25.09.99 (c) 1999, RU/2. All rights reserved.
Rewritten by Dmitry Ban. All rights ignored.