RU/2: Форум. Общение пользователей и разработчиков OS/2 (eCS). : Ответить на сообщение
Имя:
e-mail:
FIDO:
Home page:
сохранить данные о вас
Тема:
> /* 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} > }; >
__, _, __, _,_ _, _
|_ / \ |_) | | |\/|
| \ / | \ | | | |
~ ~ ~ ~ `~' ~ ~
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.