Integrate mainline.
[p5sagit/p5-mst-13.2.git] / os2 / OS2 / REXX / REXX.xs
CommitLineData
760ac839 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
17extern ULONG _emx_exception ( EXCEPTIONREPORTRECORD *,
18 EXCEPTIONREGISTRATIONRECORD *,
19 CONTEXTRECORD *,
20 void *);
21
22static RXSTRING * strs;
23static int nstrs;
24static SHVBLOCK * vars;
25static int nvars;
26static char * trace;
27
28static RXSTRING rxcommand = { 9, "RXCOMMAND" };
29static RXSTRING rxsubroutine = { 12, "RXSUBROUTINE" };
30static RXSTRING rxfunction = { 11, "RXFUNCTION" };
31
46e87256 32static ULONG PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret);
760ac839 33
34#if 1
35 #define Set RXSHV_SET
36 #define Fetch RXSHV_FETCH
37 #define Drop RXSHV_DROPV
38#else
39 #define Set RXSHV_SYSET
40 #define Fetch RXSHV_SYFET
41 #define Drop RXSHV_SYDRO
42#endif
43
44static long incompartment;
45
46static SV*
41cd3736 47exec_in_REXX(pTHX_ char *cmd, char * handlerName, RexxFunctionHandler *handler)
760ac839 48{
49 HMODULE hRexx, hRexxAPI;
50 BYTE buf[200];
51 LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING,
52 PSZ, LONG, PRXSYSEXIT, PSHORT, PRXSTRING);
53 APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ,
54 RexxFunctionHandler *);
55 APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ);
56 RXSTRING args[1];
57 RXSTRING inst[2];
58 RXSTRING result;
59 USHORT retcode;
60 LONG rc;
61 SV *res;
62
41cd3736 63 if (incompartment)
64 Perl_die(aTHX_ "Attempt to reenter into REXX compartment");
760ac839 65 incompartment = 1;
66
67 if (DosLoadModule(buf, sizeof buf, "REXX", &hRexx)
68 || DosLoadModule(buf, sizeof buf, "REXXAPI", &hRexxAPI)
69 || DosQueryProcAddr(hRexx, 0, "RexxStart", (PFN *)&pRexxStart)
70 || DosQueryProcAddr(hRexxAPI, 0, "RexxRegisterFunctionExe",
71 (PFN *)&pRexxRegisterFunctionExe)
72 || DosQueryProcAddr(hRexxAPI, 0, "RexxDeregisterFunction",
73 (PFN *)&pRexxDeregisterFunction)) {
41cd3736 74 Perl_die(aTHX_ "REXX not available\n");
760ac839 75 }
76
77 if (handlerName)
78 pRexxRegisterFunctionExe(handlerName, handler);
79
80 MAKERXSTRING(args[0], NULL, 0);
81 MAKERXSTRING(inst[0], cmd, strlen(cmd));
82 MAKERXSTRING(inst[1], NULL, 0);
83 MAKERXSTRING(result, NULL, 0);
84 rc = pRexxStart(0, args, "StartPerl", inst, "Perl", RXSUBROUTINE, NULL,
85 &retcode, &result);
86
87 incompartment = 0;
88 pRexxDeregisterFunction("StartPerl");
89 DosFreeModule(hRexxAPI);
90 DosFreeModule(hRexx);
91 if (!RXNULLSTRING(result)) {
92 res = newSVpv(RXSTRPTR(result), RXSTRLEN(result));
93 DosFreeMem(RXSTRPTR(result));
94 } else {
95 res = NEWSV(729,0);
96 }
6b88bc9c 97 if (rc || SvTRUE(GvSV(PL_errgv))) {
98 if (SvTRUE(GvSV(PL_errgv))) {
2d8e6c8d 99 STRLEN n_a;
41cd3736 100 Perl_die(aTHX_ "Error inside perl function called from REXX compartment.\n%s", SvPV(GvSV(PL_errgv), n_a)) ;
760ac839 101 }
41cd3736 102 Perl_die(aTHX_ "REXX compartment returned non-zero status %li", rc);
760ac839 103 }
104
105 return res;
106}
107
108static SV* exec_cv;
109
110static ULONG
46e87256 111PERLSTART(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret)
760ac839 112{
113 return PERLCALL(NULL, argc, argv, queue, ret);
114}
115
41cd3736 116#define in_rexx_compartment() exec_in_REXX(aTHX_ "return StartPerl()\r\n", \
760ac839 117 "StartPerl", PERLSTART)
118#define REXX_call(cv) ( exec_cv = (cv), in_rexx_compartment())
119#define REXX_eval_with(cmd,name,cv) ( exec_cv = (cv), \
41cd3736 120 exec_in_REXX(aTHX_ cmd,name,PERLSTART))
760ac839 121#define REXX_eval(cmd) REXX_eval_with(cmd,NULL,NULL)
122
123static ULONG
46e87256 124PERLCALL(PCSZ name, ULONG argc, PRXSTRING argv, PCSZ queue, PRXSTRING ret)
760ac839 125{
41cd3736 126 dTHX;
760ac839 127 EXCEPTIONREGISTRATIONRECORD xreg = { NULL, _emx_exception };
128 int i, rc;
129 unsigned long len;
130 char *str;
131 char **arr;
132 dSP;
133
134 DosSetExceptionHandler(&xreg);
135
136 ENTER;
137 SAVETMPS;
924508f0 138 PUSHMARK(SP);
760ac839 139
140#if 0
141 if (!my_perl) {
142 DosUnsetExceptionHandler(&xreg);
143 return 1;
144 }
145#endif
146
147 if (name) {
148 int ac = 0;
149 char **arr = alloca((argc + 1) * sizeof(char *));
150
151 for (i = 0; i < argc; ++i)
152 arr[ac++] = argv[i].strptr;
153 arr[ac] = NULL;
154
155 rc = perl_call_argv(name, G_SCALAR | G_EVAL, arr);
156 } else if (exec_cv) {
157 SV *cv = exec_cv;
158
159 exec_cv = NULL;
160 rc = perl_call_sv(cv, G_SCALAR | G_EVAL);
161 } else rc = -1;
162
163 SPAGAIN;
164
165 if (rc == 1 && SvOK(TOPs)) {
166 str = SvPVx(POPs, len);
167 if (len > 256)
168 if (DosAllocMem((PPVOID)&ret->strptr, len, PAG_READ|PAG_WRITE|PAG_COMMIT)) {
169 DosUnsetExceptionHandler(&xreg);
170 return 1;
171 }
172 memcpy(ret->strptr, str, len);
173 ret->strlength = len;
174 }
175
176 PUTBACK ;
177 FREETMPS ;
178 LEAVE ;
179
180 if (rc != 1) {
181 DosUnsetExceptionHandler(&xreg);
182 return 1;
183 }
184
185
186 DosUnsetExceptionHandler(&xreg);
187 return 0;
188}
189
190static void
191needstrs(int n)
192{
193 if (n > nstrs) {
194 if (strs)
195 free(strs);
196 nstrs = 2 * n;
197 strs = malloc(nstrs * sizeof(RXSTRING));
198 }
199}
200
201static void
202needvars(int n)
203{
204 if (n > nvars) {
205 if (vars)
206 free(vars);
207 nvars = 2 * n;
208 vars = malloc(nvars * sizeof(SHVBLOCK));
209 }
210}
211
212static void
213initialize(void)
214{
215 needstrs(8);
216 needvars(8);
217 trace = getenv("PERL_REXX_DEBUG");
218}
219
220static int
41cd3736 221constant(char *name, int arg)
760ac839 222{
223 errno = EINVAL;
224 return 0;
225}
226
227
228MODULE = OS2::REXX PACKAGE = OS2::REXX
229
230BOOT:
231 initialize();
232
233int
234constant(name,arg)
235 char * name
236 int arg
237
760ac839 238int
239_set(name,value,...)
240 char * name
241 char * value
242 CODE:
243 {
244 int i;
245 int n = (items + 1) / 2;
246 ULONG rc;
247 needvars(n);
248 if (trace)
249 fprintf(stderr, "REXXCALL::_set");
250 for (i = 0; i < n; ++i) {
251 SHVBLOCK * var = &vars[i];
252 STRLEN namelen;
253 STRLEN valuelen;
254 name = SvPV(ST(2*i+0),namelen);
255 if (2*i+1 < items) {
256 value = SvPV(ST(2*i+1),valuelen);
257 }
258 else {
259 value = "";
260 valuelen = 0;
261 }
262 var->shvcode = RXSHV_SET;
263 var->shvnext = &vars[i+1];
264 var->shvnamelen = namelen;
265 var->shvvaluelen = valuelen;
266 MAKERXSTRING(var->shvname, name, namelen);
267 MAKERXSTRING(var->shvvalue, value, valuelen);
268 if (trace)
269 fprintf(stderr, " %.*s='%.*s'",
270 var->shvname.strlength, var->shvname.strptr,
271 var->shvvalue.strlength, var->shvvalue.strptr);
272 }
273 if (trace)
274 fprintf(stderr, "\n");
275 vars[n-1].shvnext = NULL;
276 rc = RexxVariablePool(vars);
277 if (trace)
278 fprintf(stderr, " rc=%X\n", rc);
279 RETVAL = (rc & ~RXSHV_NEWV) ? FALSE : TRUE;
280 }
281 OUTPUT:
282 RETVAL
283
284void
285_fetch(name, ...)
286 char * name
287 PPCODE:
288 {
289 int i;
290 ULONG rc;
924508f0 291 EXTEND(SP, items);
760ac839 292 needvars(items);
293 if (trace)
294 fprintf(stderr, "REXXCALL::_fetch");
295 for (i = 0; i < items; ++i) {
296 SHVBLOCK * var = &vars[i];
297 STRLEN namelen;
298 name = SvPV(ST(i),namelen);
299 var->shvcode = RXSHV_FETCH;
300 var->shvnext = &vars[i+1];
301 var->shvnamelen = namelen;
302 var->shvvaluelen = 0;
303 MAKERXSTRING(var->shvname, name, namelen);
304 MAKERXSTRING(var->shvvalue, NULL, 0);
305 if (trace)
306 fprintf(stderr, " '%s'", name);
307 }
308 if (trace)
309 fprintf(stderr, "\n");
310 vars[items-1].shvnext = NULL;
311 rc = RexxVariablePool(vars);
312 if (!(rc & ~RXSHV_NEWV)) {
313 for (i = 0; i < items; ++i) {
314 int namelen;
315 SHVBLOCK * var = &vars[i];
316 /* returned lengths appear to be swapped */
317 /* but beware of "future bug fixes" */
318 namelen = var->shvvalue.strlength; /* should be */
319 if (var->shvvaluelen < var->shvvalue.strlength)
320 namelen = var->shvvaluelen; /* is */
321 if (trace)
322 fprintf(stderr, " %.*s='%.*s'\n",
323 var->shvname.strlength, var->shvname.strptr,
324 namelen, var->shvvalue.strptr);
325 if (var->shvret & RXSHV_NEWV || !var->shvvalue.strptr)
6b88bc9c 326 PUSHs(&PL_sv_undef);
760ac839 327 else
328 PUSHs(sv_2mortal(newSVpv(var->shvvalue.strptr,
329 namelen)));
330 }
331 } else {
332 if (trace)
333 fprintf(stderr, " rc=%X\n", rc);
334 }
335 }
336
337void
338_next(stem)
339 char * stem
340 PPCODE:
341 {
342 SHVBLOCK sv;
343 BYTE name[4096];
344 ULONG rc;
345 int len = strlen(stem), namelen, valuelen;
346 if (trace)
347 fprintf(stderr, "REXXCALL::_next stem='%s'\n", stem);
348 sv.shvcode = RXSHV_NEXTV;
349 sv.shvnext = NULL;
350 MAKERXSTRING(sv.shvvalue, NULL, 0);
351 do {
352 sv.shvnamelen = sizeof name;
353 sv.shvvaluelen = 0;
354 MAKERXSTRING(sv.shvname, name, sizeof name);
355 if (sv.shvvalue.strptr) {
356 DosFreeMem(sv.shvvalue.strptr);
357 MAKERXSTRING(sv.shvvalue, NULL, 0);
358 }
359 rc = RexxVariablePool(&sv);
360 } while (!rc && memcmp(stem, sv.shvname.strptr, len) != 0);
361 if (!rc) {
924508f0 362 EXTEND(SP, 2);
760ac839 363 /* returned lengths appear to be swapped */
364 /* but beware of "future bug fixes" */
365 namelen = sv.shvname.strlength; /* should be */
366 if (sv.shvnamelen < sv.shvname.strlength)
367 namelen = sv.shvnamelen; /* is */
368 valuelen = sv.shvvalue.strlength; /* should be */
369 if (sv.shvvaluelen < sv.shvvalue.strlength)
370 valuelen = sv.shvvaluelen; /* is */
371 if (trace)
372 fprintf(stderr, " %.*s='%.*s'\n",
373 namelen, sv.shvname.strptr,
374 valuelen, sv.shvvalue.strptr);
375 PUSHs(sv_2mortal(newSVpv(sv.shvname.strptr+len, namelen-len)));
376 if (sv.shvvalue.strptr) {
377 PUSHs(sv_2mortal(newSVpv(sv.shvvalue.strptr, valuelen)));
378 DosFreeMem(sv.shvvalue.strptr);
379 } else
6b88bc9c 380 PUSHs(&PL_sv_undef);
760ac839 381 } else if (rc != RXSHV_LVAR) {
382 die("Error %i when in _next", rc);
383 } else {
384 if (trace)
385 fprintf(stderr, " rc=%X\n", rc);
386 }
387 }
388
389int
390_drop(name,...)
391 char * name
392 CODE:
393 {
394 int i;
395 needvars(items);
396 for (i = 0; i < items; ++i) {
397 SHVBLOCK * var = &vars[i];
398 STRLEN namelen;
399 name = SvPV(ST(i),namelen);
400 var->shvcode = RXSHV_DROPV;
401 var->shvnext = &vars[i+1];
402 var->shvnamelen = namelen;
403 var->shvvaluelen = 0;
404 MAKERXSTRING(var->shvname, name, var->shvnamelen);
405 MAKERXSTRING(var->shvvalue, NULL, 0);
406 }
407 vars[items-1].shvnext = NULL;
408 RETVAL = (RexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE;
409 }
410 OUTPUT:
411 RETVAL
412
413int
414_register(name)
415 char * name
416 CODE:
417 RETVAL = RexxRegisterFunctionExe(name, PERLCALL);
418 OUTPUT:
419 RETVAL
420
421SV*
422REXX_call(cv)
423 SV *cv
424 PROTOTYPE: &
425
426SV*
427REXX_eval(cmd)
428 char *cmd
429
430SV*
431REXX_eval_with(cmd,name,cv)
432 char *cmd
433 char *name
434 SV *cv