This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Threading patches for OS/2 (missing files taken from previous patch):
[perl5.git] / os2 / OS2 / REXX / REXX.xs
CommitLineData
760ac839
LW
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
32static ULONG PERLCALL(PSZ name, ULONG argc, PRXSTRING argv, PSZ queue, PRXSTRING ret);
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*
47exec_in_REXX(char *cmd, char * handlerName, RexxFunctionHandler *handler)
48{
dd96f567 49 dTHR;
760ac839
LW
50 HMODULE hRexx, hRexxAPI;
51 BYTE buf[200];
52 LONG APIENTRY (*pRexxStart) (LONG, PRXSTRING, PSZ, PRXSTRING,
53 PSZ, LONG, PRXSYSEXIT, PSHORT, PRXSTRING);
54 APIRET APIENTRY (*pRexxRegisterFunctionExe) (PSZ,
55 RexxFunctionHandler *);
56 APIRET APIENTRY (*pRexxDeregisterFunction) (PSZ);
57 RXSTRING args[1];
58 RXSTRING inst[2];
59 RXSTRING result;
60 USHORT retcode;
61 LONG rc;
62 SV *res;
63
64 if (incompartment) die ("Attempt to reenter into REXX compartment");
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)) {
74 die("REXX not available\n");
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 }
97 if (rc || SvTRUE(GvSV(errgv))) {
98 if (SvTRUE(GvSV(errgv))) {
99 die ("Error inside perl function called from REXX compartment.\n%s", SvPV(GvSV(errgv), na)) ;
100 }
101 die ("REXX compartment returned non-zero status %li", rc);
102 }
103
104 return res;
105}
106
107static SV* exec_cv;
108
109static ULONG
110PERLSTART(PSZ name, ULONG argc, PRXSTRING argv, PSZ queue, PRXSTRING ret)
111{
112 return PERLCALL(NULL, argc, argv, queue, ret);
113}
114
115#define in_rexx_compartment() exec_in_REXX("return StartPerl()\r\n", \
116 "StartPerl", PERLSTART)
117#define REXX_call(cv) ( exec_cv = (cv), in_rexx_compartment())
118#define REXX_eval_with(cmd,name,cv) ( exec_cv = (cv), \
119 exec_in_REXX(cmd,name,PERLSTART))
120#define REXX_eval(cmd) REXX_eval_with(cmd,NULL,NULL)
121
122static ULONG
123PERLCALL(PSZ name, ULONG argc, PRXSTRING argv, PSZ queue, PRXSTRING ret)
124{
125 EXCEPTIONREGISTRATIONRECORD xreg = { NULL, _emx_exception };
126 int i, rc;
127 unsigned long len;
128 char *str;
129 char **arr;
130 dSP;
131
132 DosSetExceptionHandler(&xreg);
133
134 ENTER;
135 SAVETMPS;
136 PUSHMARK(sp);
137
138#if 0
139 if (!my_perl) {
140 DosUnsetExceptionHandler(&xreg);
141 return 1;
142 }
143#endif
144
145 if (name) {
146 int ac = 0;
147 char **arr = alloca((argc + 1) * sizeof(char *));
148
149 for (i = 0; i < argc; ++i)
150 arr[ac++] = argv[i].strptr;
151 arr[ac] = NULL;
152
153 rc = perl_call_argv(name, G_SCALAR | G_EVAL, arr);
154 } else if (exec_cv) {
155 SV *cv = exec_cv;
156
157 exec_cv = NULL;
158 rc = perl_call_sv(cv, G_SCALAR | G_EVAL);
159 } else rc = -1;
160
161 SPAGAIN;
162
163 if (rc == 1 && SvOK(TOPs)) {
164 str = SvPVx(POPs, len);
165 if (len > 256)
166 if (DosAllocMem((PPVOID)&ret->strptr, len, PAG_READ|PAG_WRITE|PAG_COMMIT)) {
167 DosUnsetExceptionHandler(&xreg);
168 return 1;
169 }
170 memcpy(ret->strptr, str, len);
171 ret->strlength = len;
172 }
173
174 PUTBACK ;
175 FREETMPS ;
176 LEAVE ;
177
178 if (rc != 1) {
179 DosUnsetExceptionHandler(&xreg);
180 return 1;
181 }
182
183
184 DosUnsetExceptionHandler(&xreg);
185 return 0;
186}
187
188static void
189needstrs(int n)
190{
191 if (n > nstrs) {
192 if (strs)
193 free(strs);
194 nstrs = 2 * n;
195 strs = malloc(nstrs * sizeof(RXSTRING));
196 }
197}
198
199static void
200needvars(int n)
201{
202 if (n > nvars) {
203 if (vars)
204 free(vars);
205 nvars = 2 * n;
206 vars = malloc(nvars * sizeof(SHVBLOCK));
207 }
208}
209
210static void
211initialize(void)
212{
213 needstrs(8);
214 needvars(8);
215 trace = getenv("PERL_REXX_DEBUG");
216}
217
218static int
219not_here(s)
220char *s;
221{
222 croak("%s not implemented on this architecture", s);
223 return -1;
224}
225
226static int
227constant(name, arg)
228char *name;
229int arg;
230{
231 errno = EINVAL;
232 return 0;
233}
234
235
236MODULE = OS2::REXX PACKAGE = OS2::REXX
237
238BOOT:
239 initialize();
240
241int
242constant(name,arg)
243 char * name
244 int arg
245
246SV *
247_call(name, address, queue="SESSION", ...)
248 char * name
249 void * address
250 char * queue
251 CODE:
252 {
253 ULONG rc;
254 int argc, i;
255 RXSTRING result;
256 UCHAR resbuf[256];
257 RexxFunctionHandler *fcn = address;
258 argc = items-3;
259 needstrs(argc);
260 if (trace)
261 fprintf(stderr, "REXXCALL::_call name: '%s' args:", name);
262 for (i = 0; i < argc; ++i) {
263 STRLEN len;
264 char *ptr = SvPV(ST(3+i), len);
265 MAKERXSTRING(strs[i], ptr, len);
266 if (trace)
267 fprintf(stderr, " '%.*s'", len, ptr);
268 }
269 if (!*queue)
270 queue = "SESSION";
271 if (trace)
272 fprintf(stderr, "\n");
273 MAKERXSTRING(result, resbuf, sizeof resbuf);
274 rc = fcn(name, argc, strs, queue, &result);
275 if (trace)
276 fprintf(stderr, " rc=%X, result='%.*s'\n", rc,
277 result.strlength, result.strptr);
278 ST(0) = sv_newmortal();
279 if (rc == 0) {
280 if (result.strptr)
281 sv_setpvn(ST(0), result.strptr, result.strlength);
282 else
283 sv_setpvn(ST(0), "", 0);
284 }
285 if (result.strptr && result.strptr != resbuf)
286 DosFreeMem(result.strptr);
287 }
288
289int
290_set(name,value,...)
291 char * name
292 char * value
293 CODE:
294 {
295 int i;
296 int n = (items + 1) / 2;
297 ULONG rc;
298 needvars(n);
299 if (trace)
300 fprintf(stderr, "REXXCALL::_set");
301 for (i = 0; i < n; ++i) {
302 SHVBLOCK * var = &vars[i];
303 STRLEN namelen;
304 STRLEN valuelen;
305 name = SvPV(ST(2*i+0),namelen);
306 if (2*i+1 < items) {
307 value = SvPV(ST(2*i+1),valuelen);
308 }
309 else {
310 value = "";
311 valuelen = 0;
312 }
313 var->shvcode = RXSHV_SET;
314 var->shvnext = &vars[i+1];
315 var->shvnamelen = namelen;
316 var->shvvaluelen = valuelen;
317 MAKERXSTRING(var->shvname, name, namelen);
318 MAKERXSTRING(var->shvvalue, value, valuelen);
319 if (trace)
320 fprintf(stderr, " %.*s='%.*s'",
321 var->shvname.strlength, var->shvname.strptr,
322 var->shvvalue.strlength, var->shvvalue.strptr);
323 }
324 if (trace)
325 fprintf(stderr, "\n");
326 vars[n-1].shvnext = NULL;
327 rc = RexxVariablePool(vars);
328 if (trace)
329 fprintf(stderr, " rc=%X\n", rc);
330 RETVAL = (rc & ~RXSHV_NEWV) ? FALSE : TRUE;
331 }
332 OUTPUT:
333 RETVAL
334
335void
336_fetch(name, ...)
337 char * name
338 PPCODE:
339 {
340 int i;
341 ULONG rc;
342 EXTEND(sp, items);
343 needvars(items);
344 if (trace)
345 fprintf(stderr, "REXXCALL::_fetch");
346 for (i = 0; i < items; ++i) {
347 SHVBLOCK * var = &vars[i];
348 STRLEN namelen;
349 name = SvPV(ST(i),namelen);
350 var->shvcode = RXSHV_FETCH;
351 var->shvnext = &vars[i+1];
352 var->shvnamelen = namelen;
353 var->shvvaluelen = 0;
354 MAKERXSTRING(var->shvname, name, namelen);
355 MAKERXSTRING(var->shvvalue, NULL, 0);
356 if (trace)
357 fprintf(stderr, " '%s'", name);
358 }
359 if (trace)
360 fprintf(stderr, "\n");
361 vars[items-1].shvnext = NULL;
362 rc = RexxVariablePool(vars);
363 if (!(rc & ~RXSHV_NEWV)) {
364 for (i = 0; i < items; ++i) {
365 int namelen;
366 SHVBLOCK * var = &vars[i];
367 /* returned lengths appear to be swapped */
368 /* but beware of "future bug fixes" */
369 namelen = var->shvvalue.strlength; /* should be */
370 if (var->shvvaluelen < var->shvvalue.strlength)
371 namelen = var->shvvaluelen; /* is */
372 if (trace)
373 fprintf(stderr, " %.*s='%.*s'\n",
374 var->shvname.strlength, var->shvname.strptr,
375 namelen, var->shvvalue.strptr);
376 if (var->shvret & RXSHV_NEWV || !var->shvvalue.strptr)
377 PUSHs(&sv_undef);
378 else
379 PUSHs(sv_2mortal(newSVpv(var->shvvalue.strptr,
380 namelen)));
381 }
382 } else {
383 if (trace)
384 fprintf(stderr, " rc=%X\n", rc);
385 }
386 }
387
388void
389_next(stem)
390 char * stem
391 PPCODE:
392 {
393 SHVBLOCK sv;
394 BYTE name[4096];
395 ULONG rc;
396 int len = strlen(stem), namelen, valuelen;
397 if (trace)
398 fprintf(stderr, "REXXCALL::_next stem='%s'\n", stem);
399 sv.shvcode = RXSHV_NEXTV;
400 sv.shvnext = NULL;
401 MAKERXSTRING(sv.shvvalue, NULL, 0);
402 do {
403 sv.shvnamelen = sizeof name;
404 sv.shvvaluelen = 0;
405 MAKERXSTRING(sv.shvname, name, sizeof name);
406 if (sv.shvvalue.strptr) {
407 DosFreeMem(sv.shvvalue.strptr);
408 MAKERXSTRING(sv.shvvalue, NULL, 0);
409 }
410 rc = RexxVariablePool(&sv);
411 } while (!rc && memcmp(stem, sv.shvname.strptr, len) != 0);
412 if (!rc) {
413 EXTEND(sp, 2);
414 /* returned lengths appear to be swapped */
415 /* but beware of "future bug fixes" */
416 namelen = sv.shvname.strlength; /* should be */
417 if (sv.shvnamelen < sv.shvname.strlength)
418 namelen = sv.shvnamelen; /* is */
419 valuelen = sv.shvvalue.strlength; /* should be */
420 if (sv.shvvaluelen < sv.shvvalue.strlength)
421 valuelen = sv.shvvaluelen; /* is */
422 if (trace)
423 fprintf(stderr, " %.*s='%.*s'\n",
424 namelen, sv.shvname.strptr,
425 valuelen, sv.shvvalue.strptr);
426 PUSHs(sv_2mortal(newSVpv(sv.shvname.strptr+len, namelen-len)));
427 if (sv.shvvalue.strptr) {
428 PUSHs(sv_2mortal(newSVpv(sv.shvvalue.strptr, valuelen)));
429 DosFreeMem(sv.shvvalue.strptr);
430 } else
431 PUSHs(&sv_undef);
432 } else if (rc != RXSHV_LVAR) {
433 die("Error %i when in _next", rc);
434 } else {
435 if (trace)
436 fprintf(stderr, " rc=%X\n", rc);
437 }
438 }
439
440int
441_drop(name,...)
442 char * name
443 CODE:
444 {
445 int i;
446 needvars(items);
447 for (i = 0; i < items; ++i) {
448 SHVBLOCK * var = &vars[i];
449 STRLEN namelen;
450 name = SvPV(ST(i),namelen);
451 var->shvcode = RXSHV_DROPV;
452 var->shvnext = &vars[i+1];
453 var->shvnamelen = namelen;
454 var->shvvaluelen = 0;
455 MAKERXSTRING(var->shvname, name, var->shvnamelen);
456 MAKERXSTRING(var->shvvalue, NULL, 0);
457 }
458 vars[items-1].shvnext = NULL;
459 RETVAL = (RexxVariablePool(vars) & ~RXSHV_NEWV) ? FALSE : TRUE;
460 }
461 OUTPUT:
462 RETVAL
463
464int
465_register(name)
466 char * name
467 CODE:
468 RETVAL = RexxRegisterFunctionExe(name, PERLCALL);
469 OUTPUT:
470 RETVAL
471
472SV*
473REXX_call(cv)
474 SV *cv
475 PROTOTYPE: &
476
477SV*
478REXX_eval(cmd)
479 char *cmd
480
481SV*
482REXX_eval_with(cmd,name,cv)
483 char *cmd
484 char *name
485 SV *cv