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