source: trunk/essentials/dev-lang/perl/os2/OS2/REXX/REXX.xs

Last change on this file was 3196, checked in by bird, 19 years ago

Missed two xreg uses.

  • Property svn:eol-style set to native
File size: 13.8 KB
Line 
1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5#define INCL_BASE
6#define INCL_REXXSAA
7#include <os2emx.h>
8
9#if 0
10#define INCL_REXXSAA
11#pragma pack(1)
12#define _Packed
13#include <rexxsaa.h>
14#pragma pack()
15#endif
16
17#ifndef __KLIBC__
18extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *,
19 EXCEPTIONREGISTRATIONRECORD *,
20 CONTEXTRECORD *,
21 void *);
22#endif
23
24static RXSTRING * strs;
25static int nstrs;
26static SHVBLOCK * vars;
27static int nvars;
28static char * trace;
29
30/*
31static RXSTRING rxcommand = { 9, "RXCOMMAND" };
32static RXSTRING rxsubroutine = { 12, "RXSUBROUTINE" };
33static RXSTRING rxfunction = { 11, "RXFUNCTION" };
34*/
35
36static ULONG PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);
37static ULONG PERLCALLcv(PCSZ name, SV *cv, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);
38static ULONG PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);
39static RexxSubcomHandler SubCommandPerlEval;
40
41#if 1
42 #define Set RXSHV_SET
43 #define Fetch RXSHV_FETCH
44 #define Drop RXSHV_DROPV
45#else
46 #define Set RXSHV_SYSET
47 #define Fetch RXSHV_SYFET
48 #define Drop RXSHV_SYDRO
49#endif
50
51static long incompartment; /* May be used to unload the REXX */
52
53static LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING,
54 PSZ, LONG, PRXSYSEXIT, PSHORT, PRXSTRING);
55static APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ,
56 RexxFunctionHandler *);
57static APIRET APIENTRY (*pRexxRegisterSubcomExe) (PCSZ pszEnvName, PFN pfnEntryPoint,
58 PUCHAR pUserArea);
59static APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ);
60
61static ULONG (*pRexxVariablePool) (PSHVBLOCK pRequest);
62
63static SV* exec_cv;
64
65/* Create a REXX compartment,
66 register `n' callbacks `handlers' with the REXX names `handlerNames',
67 evaluate the REXX expression `cmd'.
68 */
69static SV*
70exec_in_REXX_with(pTHX_ char *cmd, int c, char **handlerNames, RexxFunctionHandler **handlers)
71{
72 RXSTRING args[1];
73 RXSTRING inst[2];
74 RXSTRING result;
75 USHORT retcode;
76 LONG rc;
77 SV *res;
78 char *subs = 0;
79 int n = c, have_nl = 0;
80 char *ocmd = cmd, *s, *t;
81
82 incompartment++;
83
84 if (c)
85 Newxz(subs, c, char);
86 while (n--) {
87 rc = pRexxRegisterFunctionExe(handlerNames[n], handlers[n]);
88 if (rc == RXFUNC_DEFINED)
89 subs[n] = 1;
90 }
91
92 s = cmd;
93 while (*s) {
94 if (*s == '\n') { /* Is not preceeded by \r! */
95 Newx(cmd, 2*strlen(cmd)+1, char);
96 s = ocmd;
97 t = cmd;
98 while (*s) {
99 if (*s == '\n')
100 *t++ = '\r';
101 *t++ = *s++;
102 }
103 *t = 0;
104 break;
105 } else if (*s == '\r')
106 s++;
107 s++;
108 }
109 MAKERXSTRING(args[0], NULL, 0);
110 MAKERXSTRING(inst[0], cmd, strlen(cmd));
111 MAKERXSTRING(inst[1], NULL, 0);
112 MAKERXSTRING(result, NULL, 0);
113 rc = pRexxStart(0, args, /* No arguments */
114 "REXX_in_Perl", /* Returned on REXX' PARSE SOURCE,
115 and the "macrospace function name" */
116 inst, /* inst[0] - the code to execute,
117 inst[1] will contain tokens. */
118 "Perl", /* Pass string-cmds to this callback */
119 RXSUBROUTINE, /* Many arguments, maybe result */
120 NULL, /* No callbacks/exits to register */
121 &retcode, &result);
122
123 incompartment--;
124 n = c;
125 while (n--)
126 if (!subs[n])
127 pRexxDeregisterFunction(handlerNames[n]);
128 if (c)
129 Safefree(subs);
130 if (cmd != ocmd)
131 Safefree(cmd);
132#if 0 /* Do we want to restore these? */
133 DosFreeModule(hRexxAPI);
134 DosFreeModule(hRexx);
135#endif
136
137 if (RXSTRPTR(inst[1])) /* Free the tokenized version */
138 DosFreeMem(RXSTRPTR(inst[1]));
139 if (!RXNULLSTRING(result)) {
140 res = newSVpv(RXSTRPTR(result), RXSTRLEN(result));
141 DosFreeMem(RXSTRPTR(result));
142 } else {
143 res = NEWSV(729,0);
144 }
145 if (rc || SvTRUE(GvSV(PL_errgv))) {
146 if (SvTRUE(GvSV(PL_errgv))) {
147 STRLEN n_a;
148 Perl_croak(aTHX_ "Error inside perl function called from REXX compartment:\n%s", SvPV(GvSV(PL_errgv), n_a)) ;
149 }
150 Perl_croak(aTHX_ "REXX compartment returned non-zero status %li", rc);
151 }
152
153 return res;
154}
155
156/* Call the Perl function given by name, or if name=0, by cv,
157 with the given arguments. Return the stringified result to REXX. */
158static ULONG
159PERLCALLcv(PCSZ name, SV *cv, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret)
160{
161 dTHX;
162#ifndef __KLIBC__
163 EXCEPTIONREGISTRATIONRECORD xreg = { NULL, _emx_exception };
164#endif
165 int i, rc;
166 unsigned long len;
167 char *str;
168 SV *res;
169 dSP;
170
171#ifndef __KLIBC__
172 DosSetExceptionHandler(&xreg);
173#endif
174
175 ENTER;
176 SAVETMPS;
177 PUSHMARK(SP);
178
179#if 0
180 if (!my_perl) {
181 DosUnsetExceptionHandler(&xreg);
182 return 1;
183 }
184#endif
185
186 for (i = 0; i < argc; ++i)
187 XPUSHs(sv_2mortal(newSVpvn(argv[i].strptr, argv[i].strlength)));
188 PUTBACK;
189 if (name)
190 rc = perl_call_pv(name, G_SCALAR | G_EVAL);
191 else if (cv)
192 rc = perl_call_sv(cv, G_SCALAR | G_EVAL);
193 else
194 rc = -1;
195
196 SPAGAIN;
197
198 if (rc == 1) /* must be! */
199 res = POPs;
200 if (rc == 1 && SvOK(res)) {
201 str = SvPVx(res, len);
202 if (len <= 256 /* Default buffer is 256-char long */
203 || !CheckOSError(DosAllocMem((PPVOID)&ret->strptr, len,
204 PAG_READ|PAG_WRITE|PAG_COMMIT))) {
205 memcpy(ret->strptr, str, len);
206 ret->strlength = len;
207 } else
208 rc = 0;
209 } else
210 rc = 0;
211
212 PUTBACK ;
213 FREETMPS ;
214 LEAVE ;
215
216#ifndef __KLIBC__
217 DosUnsetExceptionHandler(&xreg);
218#endif
219 return rc == 1 ? 0 : 1; /* 0 means SUCCESS */
220}
221
222static ULONG
223PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret)
224{
225 SV *cv = exec_cv;
226
227 exec_cv = NULL;
228 return PERLCALLcv(NULL, cv, argc, argv, queue, ret);
229}
230
231static ULONG
232PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret)
233{
234 return PERLCALLcv(name, Nullsv, argc, argv, queue, ret);
235}
236
237RexxFunctionHandler* PF = &PERLSTART;
238char* PF_name = "StartPerl";
239
240#define REXX_eval_with(cmd,name,cv) \
241 ( exec_cv = cv, exec_in_REXX_with(aTHX_ (cmd),1, &(name), &PF))
242#define REXX_call(cv) REXX_eval_with("return StartPerl()\r\n", PF_name, (cv))
243#define REXX_eval(cmd) ( exec_in_REXX_with(aTHX_ (cmd), 0, NULL, NULL))
244
245static ULONG
246SubCommandPerlEval(
247 PRXSTRING command, /* command to issue */
248 PUSHORT flags, /* error/failure flags */
249 PRXSTRING retstr ) /* return code */
250{
251 dSP;
252 STRLEN len;
253 int ret;
254 char *str = 0;
255 SV *in, *res;
256
257 ENTER;
258 SAVETMPS;
259
260 PUSHMARK(SP);
261 in = sv_2mortal(newSVpvn(command->strptr, command->strlength));
262 eval_sv(in, G_SCALAR);
263 SPAGAIN;
264 res = POPs;
265 PUTBACK;
266
267 ret = 0;
268 if (SvTRUE(ERRSV)) {
269 *flags = RXSUBCOM_ERROR; /* raise error condition */
270 str = SvPV(ERRSV, len);
271 } else if (!SvOK(res)) {
272 *flags = RXSUBCOM_ERROR; /* raise error condition */
273 str = "undefined value returned by Perl-in-REXX";
274 len = strlen(str);
275 } else
276 str = SvPV(res, len);
277 if (len <= 256 /* Default buffer is 256-char long */
278 || !DosAllocMem((PPVOID)&retstr->strptr, len,
279 PAG_READ|PAG_WRITE|PAG_COMMIT)) {
280 memcpy(retstr->strptr, str, len);
281 retstr->strlength = len;
282 } else {
283 *flags = RXSUBCOM_ERROR; /* raise error condition */
284 strcpy(retstr->strptr, "Not enough memory for the return string of Perl-in-REXX");
285 retstr->strlength = strlen(retstr->strptr);
286 }
287
288 FREETMPS;
289 LEAVE;
290
291 return 0; /* finished */
292}
293
294static void
295needstrs(int n)
296{
297 if (n > nstrs) {
298 if (strs)
299 free(strs);
300 nstrs = 2 * n;
301 strs = malloc(nstrs * sizeof(RXSTRING));
302 }
303}
304
305static void
306needvars(int n)
307{
308 if (n > nvars) {
309 if (vars)
310 free(vars);
311 nvars = 2 * n;
312 vars = malloc(nvars * sizeof(SHVBLOCK));
313 }
314}
315
316static void
317initialize(void)
318{
319 ULONG rc;
320 *(PFN *)&pRexxStart = loadByOrdinal(ORD_RexxStart, 1);
321 *(PFN *)&pRexxRegisterFunctionExe
322 = loadByOrdinal(ORD_RexxRegisterFunctionExe, 1);
323 *(PFN *)&pRexxDeregisterFunction
324 = loadByOrdinal(ORD_RexxDeregisterFunction, 1);
325 *(PFN *)&pRexxVariablePool = loadByOrdinal(ORD_RexxVariablePool, 1);
326 *(PFN *)&pRexxRegisterSubcomExe
327 = loadByOrdinal(ORD_RexxRegisterSubcomExe, 1);
328 needstrs(8);
329 needvars(8);
330 trace = getenv("PERL_REXX_DEBUG");
331
332 rc = pRexxRegisterSubcomExe("PERLEVAL", (PFN)&SubCommandPerlEval, NULL);
333}
334
335static int
336constant(char *name, int arg)
337{
338 errno = EINVAL;
339 return 0;
340}
341
342
343MODULE = OS2::REXX PACKAGE = OS2::REXX
344
345BOOT:
346 initialize();
347
348int
349constant(name,arg)
350 char * name
351 int arg
352
353int
354_set(name,value,...)
355 char * name
356 char * value
357 CODE:
358 {
359 int i;
360 int n = (items + 1) / 2;
361 ULONG rc;
362 needvars(n);
363 if (trace)
364 fprintf(stderr, "REXXCALL::_set");
365 for (i = 0; i < n; ++i) {
366 SHVBLOCK * var = &vars[i];
367 STRLEN namelen;
368 STRLEN valuelen;
369 name = SvPV(ST(2*i+0),namelen);
370 if (2*i+1 < items) {
371 value = SvPV(ST(2*i+1),valuelen);
372 }
373 else {
374 value = "";
375 valuelen = 0;
376 }
377 var->shvcode = RXSHV_SET;
378 var->shvnext = &vars[i+1];
379 var->shvnamelen = namelen;
380 var->shvvaluelen = valuelen;
381 MAKERXSTRING(var->shvname, name, namelen);
382 MAKERXSTRING(var->shvvalue, value, valuelen);
383 if (trace)
384 fprintf(stderr, " %.*s='%.*s'",
385 (int)var->shvname.strlength, var->shvname.strptr,
386 (int)var->shvvalue.strlength, var->shvvalue.strptr);
387 }
388 if (trace)
389 fprintf(stderr, "\n");
390 vars[n-1].shvnext = NULL;
391 rc = pRexxVariablePool(vars);
392 if (trace)
393 fprintf(stderr, " rc=%#lX\n", rc);
394 RETVAL = (rc & ~RXSHV_NEWV) ? FALSE : TRUE;
395 }
396 OUTPUT:
397 RETVAL
398
399void
400_fetch(name, ...)
401 char * name
402 PPCODE:
403 {
404 int i;
405 ULONG rc;
406 EXTEND(SP, items);
407 needvars(items);
408 if (trace)
409 fprintf(stderr, "REXXCALL::_fetch");
410 for (i = 0; i < items; ++i) {
411 SHVBLOCK * var = &vars[i];
412 STRLEN namelen;
413 name = SvPV(ST(i),namelen);
414 var->shvcode = RXSHV_FETCH;
415 var->shvnext = &vars[i+1];
416 var->shvnamelen = namelen;
417 var->shvvaluelen = 0;
418 MAKERXSTRING(var->shvname, name, namelen);
419 MAKERXSTRING(var->shvvalue, NULL, 0);
420 if (trace)
421 fprintf(stderr, " '%s'", name);
422 }
423 if (trace)
424 fprintf(stderr, "\n");
425 vars[items-1].shvnext = NULL;
426 rc = pRexxVariablePool(vars);
427 if (!(rc & ~RXSHV_NEWV)) {
428 for (i = 0; i < items; ++i) {
429 int namelen;
430 SHVBLOCK * var = &vars[i];
431 /* returned lengths appear to be swapped */
432 /* but beware of "future bug fixes" */
433 namelen = var->shvvalue.strlength; /* should be */
434 if (var->shvvaluelen < var->shvvalue.strlength)
435 namelen = var->shvvaluelen; /* is */
436 if (trace)
437 fprintf(stderr, " %.*s='%.*s'\n",
438 (int)var->shvname.strlength, var->shvname.strptr,
439 namelen, var->shvvalue.strptr);
440 if (var->shvret & RXSHV_NEWV || !var->shvvalue.strptr)
441 PUSHs(&PL_sv_undef);
442 else
443 PUSHs(sv_2mortal(newSVpv(var->shvvalue.strptr,
444 namelen)));
445 }
446 } else {
447 if (trace)
448 fprintf(stderr, " rc=%#lX\n", rc);
449 }
450 }
451
452void
453_next(stem)
454 char * stem
455 PPCODE:
456 {
457 SHVBLOCK sv;
458 BYTE name[4096];
459 ULONG rc;
460 int len = strlen(stem), namelen, valuelen;
461 if (trace)
462 fprintf(stderr, "REXXCALL::_next stem='%s'\n", stem);
463 sv.shvcode = RXSHV_NEXTV;
464 sv.shvnext = NULL;
465 MAKERXSTRING(sv.shvvalue, NULL, 0);
466 do {
467 sv.shvnamelen = sizeof name;
468 sv.shvvaluelen = 0;
469 MAKERXSTRING(sv.shvname, name, sizeof name);
470 if (sv.shvvalue.strptr) {
471 DosFreeMem(sv.shvvalue.strptr);
472 MAKERXSTRING(sv.shvvalue, NULL, 0);
473 }
474 rc = pRexxVariablePool(&sv);
475 } while (!rc && memcmp(stem, sv.shvname.strptr, len) != 0);
476 if (!rc) {
477 EXTEND(SP, 2);
478 /* returned lengths appear to be swapped */
479 /* but beware of "future bug fixes" */
480 namelen = sv.shvname.strlength; /* should be */
481 if (sv.shvnamelen < sv.shvname.strlength)
482 namelen = sv.shvnamelen; /* is */
483 valuelen = sv.shvvalue.strlength; /* should be */
484 if (sv.shvvaluelen < sv.shvvalue.strlength)
485 valuelen = sv.shvvaluelen; /* is */
486 if (trace)
487 fprintf(stderr, " %.*s='%.*s'\n",
488 namelen, sv.shvname.strptr,
489 valuelen, sv.shvvalue.strptr);
490 PUSHs(sv_2mortal(newSVpv(sv.shvname.strptr+len, namelen-len)));
491 if (sv.shvvalue.strptr) {
492 PUSHs(sv_2mortal(newSVpv(sv.shvvalue.strptr, valuelen)));
493 DosFreeMem(sv.shvvalue.strptr);
494 } else
495 PUSHs(&PL_sv_undef);
496 } else if (rc != RXSHV_LVAR) {
497 die("Error %i when in _next", rc);
498 } else {
499 if (trace)
500 fprintf(stderr, " rc=%#lX\n", rc);
501 }
502 }
503
504int
505_drop(name,...)
506 char * name
507 CODE:
508 {
509 int i;
510 needvars(items);
511 for (i = 0; i < items; ++i) {
512 SHVBLOCK * var = &vars[i];
513 STRLEN namelen;
514 name = SvPV(ST(i),namelen);
515 var->shvcode = RXSHV_DROPV;
516 var->shvnext = &vars[i+1];
517 var->shvnamelen = namelen;
518 var->shvvaluelen = 0;
519 MAKERXSTRING(var->shvname, name, var->shvnamelen);
520 MAKERXSTRING(var->shvvalue, NULL, 0);
521 }
522 vars[items-1].shvnext = NULL;
523 RETVAL = (pRexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE;
524 }
525 OUTPUT:
526 RETVAL
527
528int
529_register(name)
530 char * name
531 CODE:
532 RETVAL = pRexxRegisterFunctionExe(name, PERLCALL);
533 OUTPUT:
534 RETVAL
535
536SV*
537REXX_call(cv)
538 SV *cv
539 PROTOTYPE: &
540
541SV*
542REXX_eval(cmd)
543 char *cmd
544
545SV*
546REXX_eval_with(cmd,name,cv)
547 char *cmd
548 char *name
549 SV *cv
550
551#ifdef THIS_IS_NOT_FINISHED
552
553SV*
554_REXX_eval_with(cmd,...)
555 char *cmd
556 CODE:
557 {
558 int n = (items - 1)/2;
559 char **names;
560 SV **cvs;
561
562 if ((items % 2) == 0)
563 Perl_croak(aTHX_ "Name/values should come in pairs in REXX_eval_with()");
564 Newx(names, n, char*);
565 Newx(cvs, n, SV*);
566 /* XXX Unfinished... */
567 RETVAL = Nullsv;
568 Safefree(names);
569 Safefree(cvs);
570 }
571 OUTPUT:
572 RETVAL
573
574#endif
Note: See TracBrowser for help on using the repository browser.