1 #include "EXTERN.h" 2 #include "perl.h" 3 #include "XSUB.h" 4 5 #undef __USE_INLINE__ 6 #include <exec/types.h> 7 #include <utility/tagitem.h> 8 #include <proto/exec.h> 9 #include <proto/intuition.h> 10 #include <proto/rexxsyslib.h> 11 #include <proto/utility.h> 12 13 #include <rexx/rxslib.h> 14 #include <rexx/errors.h> 15 //#include "rexxmsgext.h" // this should change depening on the ultimate location of the structures 16 17 /* utils */ 18 19 /* 20 * Structure for the rexx host. Most of the code is inspired from Olaf 21 * Barthel's sample ARexx code from the developer CD 2.1 22 */ 23 24 25 struct RexxHost 26 { 27 struct MsgPort *Port; 28 TEXT PortName[81]; 29 } ; 30 31 struct ARexxMsg 32 { 33 struct RexxMsg *rexxMsg; 34 BOOL isReplied; 35 struct RexxHost *rexxHost; 36 }; 37 38 STRPTR dupstr(STRPTR src) 39 { 40 STRPTR dest = NULL; 41 ULONG len; 42 if(src) 43 { 44 len = strlen(src); 45 if((dest = IExec->AllocVec(len + 1, MEMF_ANY))) 46 { 47 strcpy(dest,src); 48 } 49 } 50 return dest; 51 } 52 53 54 struct TimeRequest * 55 OpenTimer(void) 56 { 57 struct MsgPort *port = IExec->AllocSysObjectTags(ASOT_PORT, TAG_END); 58 if (port == NULL) 59 { 60 return NULL; 61 } 62 63 struct TimeRequest *req = IExec->AllocSysObjectTags(ASOT_IOREQUEST, 64 ASOIOR_Size, sizeof(struct TimeRequest), 65 ASOIOR_ReplyPort, port, 66 TAG_END); 67 68 if (req == NULL) 69 { 70 IExec->FreeSysObject(ASOT_PORT, port); 71 return NULL; 72 } 73 74 int8 deverr = IExec->OpenDevice("timer.device", UNIT_MICROHZ, 75 &req->Request, 0); 76 77 if (deverr != IOERR_SUCCESS) 78 { 79 IExec->FreeSysObject(ASOT_IOREQUEST, req); 80 IExec->FreeSysObject(ASOT_PORT, port); 81 return NULL; 82 } 83 84 return req; 85 } 86 87 88 void 89 CloseTimer(struct TimeRequest *req) 90 { 91 if (req != NULL) 92 { 93 struct MsgPort *port = req->Request.io_Message.mn_ReplyPort; 94 95 IExec->CloseDevice(&req->Request); 96 IExec->FreeSysObject(ASOT_IOREQUEST, req); 97 IExec->FreeSysObject(ASOT_PORT, port); 98 } 99 } 100 101 LONG 102 ReturnRexxMsg(struct RexxMsg * Message, CONST_STRPTR Result) 103 { 104 STRPTR ResultString = NULL; 105 106 /* No error has occured yet. */ 107 int32 ErrorCode = 0; 108 109 /* Set up the RexxMsg to return no error. */ 110 Message->rm_Result1 = RC_OK; 111 Message->rm_Result2 = 0; 112 113 /* Check if the command should return a result. */ 114 if((Message->rm_Action & RXFF_RESULT) && Result != NULL) 115 { 116 /* To return the result string we need to make 117 * a copy for ARexx to use. 118 */ 119 if((ResultString = IRexxSys->CreateArgstring(Result, strlen(Result)))) 120 { 121 /* Put the string into the secondary 122 * result field. 123 */ 124 Message->rm_Result2 = (LONG)ResultString; 125 } 126 else 127 { 128 /* No memory available. */ 129 ErrorCode = ERR10_003; 130 } 131 } 132 133 /* Reply the message, regardless of the error code. */ 134 IExec->ReplyMsg((struct Message *)Message); 135 136 return(ErrorCode); 137 } 138 139 140 void 141 ReturnErrorMsg(struct RexxMsg *msg, CONST_STRPTR port, int32 rc, int32 rc2) 142 { 143 /* To signal an error the rc_Result1 144 * entry of the RexxMsg needs to be set to 145 * RC_ERROR. Unfortunately, we cannot convey 146 * the more meaningful error code through 147 * this interface which is why we set a 148 * Rexx variable to the error number. The 149 * Rexx script can then take a look at this 150 * variable and decide which further steps 151 * it should take. 152 */ 153 msg->rm_Result1 = rc; 154 msg->rm_Result2 = rc2; 155 156 /* Turn the error number into a string as 157 * ARexx only deals with strings. 158 */ 159 char value[12]; 160 IUtility->SNPrintf(value, sizeof(value), "%ld", rc2); 161 162 /* Build the name of the variable to set to 163 * the error number. We will use the name of 164 * the host name and append ".LASTERROR". 165 */ 166 IRexxSys->SetRexxVarFromMsg("RC2", value, msg); 167 168 IExec->ReplyMsg(&msg->rm_Node); 169 } 170 171 BOOL 172 PutMsgTo(CONST_STRPTR name, struct Message *msg) 173 { 174 BOOL done = FALSE; 175 176 IExec->Forbid(); 177 178 struct MsgPort *port = IExec->FindPort(name); 179 if (port != NULL) 180 { 181 IExec->PutMsg(port, msg); 182 done = TRUE; 183 } 184 185 IExec->Permit(); 186 187 return done; 188 } 189 190 191 STRPTR DoRexx(STRPTR port, STRPTR command, int32 *rc, int32 *rc2) 192 { 193 *rc = 0; 194 *rc2 = 0; 195 STRPTR result = NULL; 196 STRPTR dup = NULL; 197 198 struct MsgPort *replyPort = IExec->AllocSysObjectTags(ASOT_PORT, TAG_END); 199 if (replyPort == NULL) 200 { 201 return NULL; 202 } 203 204 struct RexxMsg *rexxMsg = IRexxSys->CreateRexxMsg(replyPort, NULL, NULL); 205 ((struct Node *)rexxMsg)->ln_Name = "REXX"; 206 if (rexxMsg == NULL) 207 { 208 IExec->FreeSysObject(ASOT_PORT, replyPort); 209 return NULL; 210 } 211 BOOL sent = FALSE; 212 213 214 rexxMsg->rm_Args[0] = IRexxSys->CreateArgstring(command, strlen(command)); 215 216 if (rexxMsg->rm_Args[0] != NULL) 217 { 218 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT | RXFF_STRING; 219 220 sent = PutMsgTo(port, (struct Message*)rexxMsg); 221 222 if (sent) 223 { 224 IExec->WaitPort(replyPort); 225 (void)IExec->GetMsg(replyPort); 226 } 227 else 228 { 229 230 } 231 232 *rc = rexxMsg->rm_Result1; 233 234 if (*rc == RC_OK) 235 { 236 if (rexxMsg->rm_Result2 != 0) 237 { 238 result = (STRPTR)rexxMsg->rm_Result2; 239 } 240 } 241 else 242 { 243 *rc2 = rexxMsg->rm_Result2; 244 } 245 246 IRexxSys->DeleteArgstring(rexxMsg->rm_Args[0]); 247 rexxMsg->rm_Args[0] = NULL; 248 } 249 250 IRexxSys->DeleteRexxMsg(rexxMsg); 251 rexxMsg = NULL; 252 253 IExec->FreeSysObject(ASOT_PORT, replyPort); 254 replyPort = NULL; 255 256 if (result != NULL) 257 { 258 dup = dupstr(result); 259 260 IRexxSys->DeleteArgstring(result); 261 result = NULL; 262 } 263 264 return dup; 265 } 266 267 268 struct RexxHost *CreateRexxHost(CONST_STRPTR PortName) 269 { 270 struct RexxHost *newHost = IExec->AllocVecTags(sizeof(struct RexxHost), 271 AVT_Type, MEMF_PRIVATE, AVT_ClearWithValue, 0, TAG_DONE); 272 273 if (newHost == NULL) 274 { 275 return NULL; 276 } 277 278 IUtility->Strlcpy(newHost->PortName, PortName, sizeof(newHost->PortName)); 279 280 IExec->Forbid(); 281 282 /* Check if the name already exists */ 283 if (IExec->FindPort(PortName) != NULL) 284 { 285 int32 index = 1; 286 do 287 { 288 IUtility->SNPrintf(newHost->PortName, sizeof(newHost->PortName), "%s.%ld", PortName, index); 289 index++; 290 291 if (IExec->FindPort(newHost->PortName) == NULL) 292 { 293 break; 294 } 295 } while (1); 296 } 297 298 newHost->Port = IExec->AllocSysObjectTags(ASOT_PORT, 299 ASOPORT_Name, newHost->PortName, 300 ASOPORT_Public, TRUE, 301 TAG_DONE); 302 303 IExec->Permit(); 304 305 if (newHost->Port == NULL) 306 { 307 IExec->FreeVec(newHost); 308 return NULL; 309 } 310 311 return newHost; 312 } 313 314 315 void DeleteRexxHost(struct RexxHost *host) 316 { 317 if (host) 318 { 319 if (host->Port) 320 { 321 struct RexxMsg *msg; 322 323 IExec->Forbid(); 324 while ((msg = (struct RexxMsg *)IExec->GetMsg(host->Port)) != NULL) 325 { 326 msg->rm_Result1 = RC_FATAL; 327 IExec->ReplyMsg((struct Message *)msg); 328 } 329 330 IExec->FreeSysObject(ASOT_PORT, host->Port); 331 IExec->Permit(); 332 } 333 334 IExec->FreeVec(host); 335 } 336 } 337 338 void WaitRexxHost(struct RexxHost *rexxHost, int timeout) 339 { 340 341 struct TimeRequest *req = NULL; 342 uint32 timermask = 0; 343 344 if (timeout > 0) 345 { 346 req = OpenTimer(); 347 348 if (req != NULL) 349 { 350 timermask = 1L << req->Request.io_Message.mn_ReplyPort->mp_SigBit; 351 352 req->Request.io_Command = TR_ADDREQUEST; 353 req->Time.Seconds = 0; 354 req->Time.Microseconds = timeout; 355 356 IExec->SendIO(&req->Request); 357 } 358 } 359 360 uint32 hostmask = 1L << rexxHost->Port->mp_SigBit; 361 uint32 waitmask = timermask | hostmask | SIGBREAKF_CTRL_C; 362 363 uint32 sigmask = IExec->Wait(waitmask); 364 365 if (req != NULL) 366 { 367 IExec->AbortIO(&req->Request); 368 IExec->WaitIO(&req->Request); 369 CloseTimer(req); 370 } 371 372 if (sigmask & SIGBREAKF_CTRL_C) 373 { 374 return; 375 } 376 377 378 } 379 380 struct ARexxMsg *GetMsgRexxHost(struct RexxHost *rexxHost) 381 { 382 struct ARexxMsg *am = NULL; 383 384 struct RexxMsg *rexxMsg = NULL; 385 386 rexxMsg = (struct RexxMsg *)IExec->GetMsg(rexxHost->Port); 387 if (rexxMsg != NULL) 388 { 389 if((am = IExec->AllocVecTags(sizeof(struct ARexxMsg),AVT_Type, MEMF_PRIVATE, AVT_ClearWithValue, 0, TAG_DONE))) 390 { 391 am->rexxMsg = rexxMsg; 392 am->rexxHost = rexxHost; 393 am->isReplied = FALSE; 394 } 395 396 } 397 return am; 398 } 399 400 uint32 GetSignalRexxHost(struct RexxHost *rexxHost) 401 { 402 return rexxHost->Port->mp_SigBit; 403 } 404 405 406 void ReplyARexxMsg(struct ARexxMsg *am, int rc, int rc2, STRPTR result) 407 { 408 if(am) 409 { 410 if(!am->isReplied) 411 { 412 if(rc == 0) 413 { 414 ReturnRexxMsg(am->rexxMsg, result); 415 } 416 else 417 { 418 ReturnErrorMsg(am->rexxMsg, am->rexxHost->PortName,rc,rc2); 419 } 420 am->isReplied = TRUE; 421 } 422 } 423 } 424 425 STRPTR GetVarARexxMsg(struct ARexxMsg *am, STRPTR varname) 426 { 427 STRPTR result = IExec->AllocVecTags(256,AVT_Type, MEMF_PRIVATE, AVT_ClearWithValue, 0, TAG_DONE); 428 if(result) 429 { 430 IRexxSys->GetRexxVarFromMsg(varname, result, am->rexxMsg); 431 } 432 return result; 433 } 434 435 void SetVarARexxMsg(struct ARexxMsg *am, STRPTR varname, STRPTR value) 436 { 437 IRexxSys->SetRexxVarFromMsg(varname, value, am->rexxMsg); 438 } 439 440 void DeleteARexxMsg(struct ARexxMsg *am) 441 { 442 if(!am->isReplied) 443 { 444 IExec->ReplyMsg(&am->rexxMsg->rm_Node); 445 am->isReplied = TRUE; 446 } 447 IExec->FreeVec(am); 448 } 449 450 STRPTR GetArgsARexxMsg(struct ARexxMsg *am) 451 { 452 return am->rexxMsg->rm_Args[0]; 453 } 454 455 MODULE = Amiga::ARexx PACKAGE = Amiga::ARexx 456 457 PROTOTYPES: DISABLE 458 459 460 APTR Host_init(name) 461 STRPTR name; 462 CODE: 463 RETVAL = CreateRexxHost(name); 464 OUTPUT: 465 RETVAL 466 467 void Host_delete(rexxhost) 468 APTR rexxhost; 469 CODE: 470 DeleteRexxHost(rexxhost); 471 472 void Host_wait(rexxhost,timeout) 473 APTR rexxhost 474 int timeout 475 CODE: 476 WaitRexxHost(rexxhost,timeout); 477 478 uint32 Host_signal(rexxhost) 479 APTR rexxhost 480 CODE: 481 RETVAL = GetSignalRexxHost(rexxhost); 482 OUTPUT: 483 RETVAL 484 485 APTR Host_getmsg(rexxhost) 486 APTR rexxhost 487 CODE: 488 RETVAL = GetMsgRexxHost(rexxhost); 489 OUTPUT: 490 RETVAL 491 492 void Msg_reply(rexxmsg,rc,rc2,result) 493 APTR rexxmsg 494 int rc 495 int rc2 496 STRPTR result 497 CODE: 498 ReplyARexxMsg(rexxmsg,rc,rc2,result); 499 500 void Msg_delete(rexxmsg) 501 APTR rexxmsg 502 CODE: 503 DeleteARexxMsg(rexxmsg); 504 505 STRPTR Msg_argstr(rexxmsg) 506 APTR rexxmsg 507 CODE: 508 RETVAL = GetArgsARexxMsg(rexxmsg); 509 OUTPUT: 510 RETVAL 511 512 STRPTR Msg_getvar(rexxmsg,varname) 513 APTR rexxmsg 514 STRPTR varname 515 PPCODE: 516 RETVAL = GetVarARexxMsg(rexxmsg,varname); 517 sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; 518 if (RETVAL) IExec->FreeVec(RETVAL); 519 520 void Msg_setvar(rexxmsg,varname,value) 521 APTR rexxmsg 522 STRPTR varname 523 STRPTR value 524 CODE: 525 SetVarARexxMsg(rexxmsg,varname,value); 526 527 STRPTR _DoRexx(port,command,rc,rc2) 528 STRPTR port 529 STRPTR command 530 int32 &rc 531 int32 &rc2 532 PPCODE: 533 RETVAL = DoRexx(port,command,&rc,&rc2); 534 sv_setiv(ST(2), (IV)rc); 535 SvSETMAGIC(ST(2)); 536 sv_setiv(ST(3), (IV)rc2); 537 SvSETMAGIC(ST(3)); 538 sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG; 539 IExec->FreeVec(RETVAL); 540 541