📄 rexx.xs
字号:
#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#define INCL_BASE#define INCL_REXXSAA#include <os2emx.h>#if 0#define INCL_REXXSAA#pragma pack(1)#define _Packed#include <rexxsaa.h>#pragma pack()#endifextern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *, EXCEPTIONREGISTRATIONRECORD *, CONTEXTRECORD *, void *);static RXSTRING * strs;static int nstrs;static SHVBLOCK * vars;static int nvars;static char * trace;/*static RXSTRING rxcommand = { 9, "RXCOMMAND" };static RXSTRING rxsubroutine = { 12, "RXSUBROUTINE" };static RXSTRING rxfunction = { 11, "RXFUNCTION" };*/static ULONG PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);static ULONG PERLCALLcv(PCSZ name, SV *cv, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);static ULONG PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);static RexxSubcomHandler SubCommandPerlEval;#if 1 #define Set RXSHV_SET #define Fetch RXSHV_FETCH #define Drop RXSHV_DROPV#else #define Set RXSHV_SYSET #define Fetch RXSHV_SYFET #define Drop RXSHV_SYDRO#endifstatic long incompartment; /* May be used to unload the REXX */static LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING, PSZ, LONG, PRXSYSEXIT, PSHORT, PRXSTRING);static APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ, RexxFunctionHandler *);static APIRET APIENTRY (*pRexxRegisterSubcomExe) (PCSZ pszEnvName, PFN pfnEntryPoint, PUCHAR pUserArea);static APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ);static ULONG (*pRexxVariablePool) (PSHVBLOCK pRequest);static SV* exec_cv;/* Create a REXX compartment, register `n' callbacks `handlers' with the REXX names `handlerNames', evaluate the REXX expression `cmd'. */static SV*exec_in_REXX_with(pTHX_ char *cmd, int c, char **handlerNames, RexxFunctionHandler **handlers){ RXSTRING args[1]; RXSTRING inst[2]; RXSTRING result; USHORT retcode; LONG rc; SV *res; char *subs = 0; int n = c, have_nl = 0; char *ocmd = cmd, *s, *t; incompartment++; if (c) Newxz(subs, c, char); while (n--) { rc = pRexxRegisterFunctionExe(handlerNames[n], handlers[n]); if (rc == RXFUNC_DEFINED) subs[n] = 1; } s = cmd; while (*s) { if (*s == '\n') { /* Is not preceeded by \r! */ Newx(cmd, 2*strlen(cmd)+1, char); s = ocmd; t = cmd; while (*s) { if (*s == '\n') *t++ = '\r'; *t++ = *s++; } *t = 0; break; } else if (*s == '\r') s++; s++; } MAKERXSTRING(args[0], NULL, 0); MAKERXSTRING(inst[0], cmd, strlen(cmd)); MAKERXSTRING(inst[1], NULL, 0); MAKERXSTRING(result, NULL, 0); rc = pRexxStart(0, args, /* No arguments */ "REXX_in_Perl", /* Returned on REXX' PARSE SOURCE, and the "macrospace function name" */ inst, /* inst[0] - the code to execute, inst[1] will contain tokens. */ "Perl", /* Pass string-cmds to this callback */ RXSUBROUTINE, /* Many arguments, maybe result */ NULL, /* No callbacks/exits to register */ &retcode, &result); incompartment--; n = c; while (n--) if (!subs[n]) pRexxDeregisterFunction(handlerNames[n]); if (c) Safefree(subs); if (cmd != ocmd) Safefree(cmd);#if 0 /* Do we want to restore these? */ DosFreeModule(hRexxAPI); DosFreeModule(hRexx);#endif if (RXSTRPTR(inst[1])) /* Free the tokenized version */ DosFreeMem(RXSTRPTR(inst[1])); if (!RXNULLSTRING(result)) { res = newSVpv(RXSTRPTR(result), RXSTRLEN(result)); DosFreeMem(RXSTRPTR(result)); } else { res = newSV(0); } if (rc || SvTRUE(GvSV(PL_errgv))) { if (SvTRUE(GvSV(PL_errgv))) { STRLEN n_a; Perl_croak(aTHX_ "Error inside perl function called from REXX compartment:\n%s", SvPV(GvSV(PL_errgv), n_a)) ; } Perl_croak(aTHX_ "REXX compartment returned non-zero status %li", rc); } return res;}/* Call the Perl function given by name, or if name=0, by cv, with the given arguments. Return the stringified result to REXX. */static ULONGPERLCALLcv(PCSZ name, SV *cv, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret){ dTHX; EXCEPTIONREGISTRATIONRECORD xreg = { NULL, _emx_exception }; int i, rc; unsigned long len; char *str; SV *res; dSP; DosSetExceptionHandler(&xreg); ENTER; SAVETMPS; PUSHMARK(SP);#if 0 if (!my_perl) { DosUnsetExceptionHandler(&xreg); return 1; }#endif for (i = 0; i < argc; ++i) XPUSHs(sv_2mortal(newSVpvn(argv[i].strptr, argv[i].strlength))); PUTBACK; if (name) rc = perl_call_pv(name, G_SCALAR | G_EVAL); else if (cv) rc = perl_call_sv(cv, G_SCALAR | G_EVAL); else rc = -1; SPAGAIN; if (rc == 1) /* must be! */ res = POPs; if (rc == 1 && SvOK(res)) { str = SvPVx(res, len); if (len <= 256 /* Default buffer is 256-char long */ || !CheckOSError(DosAllocMem((PPVOID)&ret->strptr, len, PAG_READ|PAG_WRITE|PAG_COMMIT))) { memcpy(ret->strptr, str, len); ret->strlength = len; } else rc = 0; } else rc = 0; PUTBACK ; FREETMPS ; LEAVE ; DosUnsetExceptionHandler(&xreg); return rc == 1 ? 0 : 1; /* 0 means SUCCESS */}static ULONGPERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret){ SV *cv = exec_cv; exec_cv = NULL; return PERLCALLcv(NULL, cv, argc, argv, queue, ret);}static ULONGPERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret){ return PERLCALLcv(name, Nullsv, argc, argv, queue, ret);}RexxFunctionHandler* PF = &PERLSTART;char* PF_name = "StartPerl";#define REXX_eval_with(cmd,name,cv) \ ( exec_cv = cv, exec_in_REXX_with(aTHX_ (cmd),1, &(name), &PF))#define REXX_call(cv) REXX_eval_with("return StartPerl()\r\n", PF_name, (cv))#define REXX_eval(cmd) ( exec_in_REXX_with(aTHX_ (cmd), 0, NULL, NULL))static ULONGSubCommandPerlEval( PRXSTRING command, /* command to issue */ PUSHORT flags, /* error/failure flags */ PRXSTRING retstr ) /* return code */{ dSP; STRLEN len; int ret; char *str = 0; SV *in, *res; ENTER; SAVETMPS; PUSHMARK(SP); in = sv_2mortal(newSVpvn(command->strptr, command->strlength)); eval_sv(in, G_SCALAR); SPAGAIN; res = POPs; PUTBACK; ret = 0; if (SvTRUE(ERRSV)) { *flags = RXSUBCOM_ERROR; /* raise error condition */ str = SvPV(ERRSV, len); } else if (!SvOK(res)) { *flags = RXSUBCOM_ERROR; /* raise error condition */ str = "undefined value returned by Perl-in-REXX"; len = strlen(str); } else str = SvPV(res, len); if (len <= 256 /* Default buffer is 256-char long */ || !DosAllocMem((PPVOID)&retstr->strptr, len, PAG_READ|PAG_WRITE|PAG_COMMIT)) { memcpy(retstr->strptr, str, len); retstr->strlength = len; } else { *flags = RXSUBCOM_ERROR; /* raise error condition */ strcpy(retstr->strptr, "Not enough memory for the return string of Perl-in-REXX"); retstr->strlength = strlen(retstr->strptr); } FREETMPS; LEAVE; return 0; /* finished */}static voidneedstrs(int n){ if (n > nstrs) { if (strs) free(strs); nstrs = 2 * n; strs = malloc(nstrs * sizeof(RXSTRING)); }}static voidneedvars(int n){ if (n > nvars) { if (vars) free(vars); nvars = 2 * n; vars = malloc(nvars * sizeof(SHVBLOCK)); }}static voidinitialize(void){ ULONG rc; *(PFN *)&pRexxStart = loadByOrdinal(ORD_RexxStart, 1); *(PFN *)&pRexxRegisterFunctionExe = loadByOrdinal(ORD_RexxRegisterFunctionExe, 1); *(PFN *)&pRexxDeregisterFunction = loadByOrdinal(ORD_RexxDeregisterFunction, 1); *(PFN *)&pRexxVariablePool = loadByOrdinal(ORD_RexxVariablePool, 1); *(PFN *)&pRexxRegisterSubcomExe = loadByOrdinal(ORD_RexxRegisterSubcomExe, 1); needstrs(8); needvars(8); trace = getenv("PERL_REXX_DEBUG"); rc = pRexxRegisterSubcomExe("PERLEVAL", (PFN)&SubCommandPerlEval, NULL);}static intconstant(char *name, int arg){ errno = EINVAL; return 0;}MODULE = OS2::REXX PACKAGE = OS2::REXXBOOT: initialize();intconstant(name,arg) char * name int argint_set(name,value,...) char * name char * value CODE: { int i; int n = (items + 1) / 2; ULONG rc; needvars(n); if (trace) fprintf(stderr, "REXXCALL::_set"); for (i = 0; i < n; ++i) { SHVBLOCK * var = &vars[i]; STRLEN namelen; STRLEN valuelen; name = SvPV(ST(2*i+0),namelen); if (2*i+1 < items) { value = SvPV(ST(2*i+1),valuelen); } else { value = ""; valuelen = 0; } var->shvcode = RXSHV_SET; var->shvnext = &vars[i+1]; var->shvnamelen = namelen; var->shvvaluelen = valuelen; MAKERXSTRING(var->shvname, name, namelen); MAKERXSTRING(var->shvvalue, value, valuelen); if (trace) fprintf(stderr, " %.*s='%.*s'", (int)var->shvname.strlength, var->shvname.strptr, (int)var->shvvalue.strlength, var->shvvalue.strptr); } if (trace) fprintf(stderr, "\n"); vars[n-1].shvnext = NULL; rc = pRexxVariablePool(vars); if (trace) fprintf(stderr, " rc=%#lX\n", rc); RETVAL = (rc & ~RXSHV_NEWV) ? FALSE : TRUE; } OUTPUT: RETVALvoid_fetch(name, ...) char * name PPCODE: { int i; ULONG rc; EXTEND(SP, items); needvars(items); if (trace) fprintf(stderr, "REXXCALL::_fetch"); for (i = 0; i < items; ++i) { SHVBLOCK * var = &vars[i]; STRLEN namelen; name = SvPV(ST(i),namelen); var->shvcode = RXSHV_FETCH; var->shvnext = &vars[i+1]; var->shvnamelen = namelen; var->shvvaluelen = 0; MAKERXSTRING(var->shvname, name, namelen); MAKERXSTRING(var->shvvalue, NULL, 0); if (trace) fprintf(stderr, " '%s'", name); } if (trace) fprintf(stderr, "\n"); vars[items-1].shvnext = NULL; rc = pRexxVariablePool(vars); if (!(rc & ~RXSHV_NEWV)) { for (i = 0; i < items; ++i) { int namelen; SHVBLOCK * var = &vars[i]; /* returned lengths appear to be swapped */ /* but beware of "future bug fixes" */ namelen = var->shvvalue.strlength; /* should be */ if (var->shvvaluelen < var->shvvalue.strlength) namelen = var->shvvaluelen; /* is */ if (trace) fprintf(stderr, " %.*s='%.*s'\n", (int)var->shvname.strlength, var->shvname.strptr, namelen, var->shvvalue.strptr); if (var->shvret & RXSHV_NEWV || !var->shvvalue.strptr) PUSHs(&PL_sv_undef); else PUSHs(sv_2mortal(newSVpv(var->shvvalue.strptr, namelen))); } } else { if (trace) fprintf(stderr, " rc=%#lX\n", rc); } }void_next(stem) char * stem PPCODE: { SHVBLOCK sv; BYTE name[4096]; ULONG rc; int len = strlen(stem), namelen, valuelen; if (trace) fprintf(stderr, "REXXCALL::_next stem='%s'\n", stem); sv.shvcode = RXSHV_NEXTV; sv.shvnext = NULL; MAKERXSTRING(sv.shvvalue, NULL, 0); do { sv.shvnamelen = sizeof name; sv.shvvaluelen = 0; MAKERXSTRING(sv.shvname, name, sizeof name); if (sv.shvvalue.strptr) { DosFreeMem(sv.shvvalue.strptr); MAKERXSTRING(sv.shvvalue, NULL, 0); } rc = pRexxVariablePool(&sv); } while (!rc && memcmp(stem, sv.shvname.strptr, len) != 0); if (!rc) { EXTEND(SP, 2); /* returned lengths appear to be swapped */ /* but beware of "future bug fixes" */ namelen = sv.shvname.strlength; /* should be */ if (sv.shvnamelen < sv.shvname.strlength) namelen = sv.shvnamelen; /* is */ valuelen = sv.shvvalue.strlength; /* should be */ if (sv.shvvaluelen < sv.shvvalue.strlength) valuelen = sv.shvvaluelen; /* is */ if (trace) fprintf(stderr, " %.*s='%.*s'\n", namelen, sv.shvname.strptr, valuelen, sv.shvvalue.strptr); PUSHs(sv_2mortal(newSVpv(sv.shvname.strptr+len, namelen-len))); if (sv.shvvalue.strptr) { PUSHs(sv_2mortal(newSVpv(sv.shvvalue.strptr, valuelen))); DosFreeMem(sv.shvvalue.strptr); } else PUSHs(&PL_sv_undef); } else if (rc != RXSHV_LVAR) { die("Error %i when in _next", rc); } else { if (trace) fprintf(stderr, " rc=%#lX\n", rc); } }int_drop(name,...) char * name CODE: { int i; needvars(items); for (i = 0; i < items; ++i) { SHVBLOCK * var = &vars[i]; STRLEN namelen; name = SvPV(ST(i),namelen); var->shvcode = RXSHV_DROPV; var->shvnext = &vars[i+1]; var->shvnamelen = namelen; var->shvvaluelen = 0; MAKERXSTRING(var->shvname, name, var->shvnamelen); MAKERXSTRING(var->shvvalue, NULL, 0); } vars[items-1].shvnext = NULL; RETVAL = (pRexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE; } OUTPUT: RETVALint_register(name) char * name CODE: RETVAL = pRexxRegisterFunctionExe(name, PERLCALL); OUTPUT: RETVALSV*REXX_call(cv) SV *cv PROTOTYPE: &SV*REXX_eval(cmd) char *cmdSV*REXX_eval_with(cmd,name,cv) char *cmd char *name SV *cv#ifdef THIS_IS_NOT_FINISHEDSV*_REXX_eval_with(cmd,...) char *cmd CODE: { int n = (items - 1)/2; char **names; SV **cvs; if ((items % 2) == 0) Perl_croak(aTHX_ "Name/values should come in pairs in REXX_eval_with()"); Newx(names, n, char*); Newx(cvs, n, SV*); /* XXX Unfinished... */ RETVAL = Nullsv; Safefree(names); Safefree(cvs); } OUTPUT: RETVAL#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -