make sure "S" is generated.
[AROS-Contrib.git] / bgui / arexxclass.c
blobaa25e19502779a0d086755192dde9ea872304381
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * arexxclass.c
7 * (C) Copyright 1998 Manuel Lemos.
8 * (C) Copyright 1996-1997 Ian J. Einman.
9 * (C) Copyright 1993-1996 Jaba Development.
10 * (C) Copyright 1993-1996 Jan van den Baard.
11 * All Rights Reserved.
13 * $Log$
14 * Revision 42.3 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.2 2000/08/08 20:57:26 chodorowski
18 * Minor fixes to build on Amiga.
20 * Revision 42.1 2000/05/15 19:27:00 stegerg
21 * another hundreds of REG() macro replacements in func headers/protos.
23 * Revision 42.0 2000/05/09 22:08:13 mlemos
24 * Bumped to revision 42.0 before handing BGUI to AROS team
26 * Revision 41.11 2000/05/09 20:21:32 mlemos
27 * Bumped to revision 41.11
29 * Revision 41.1 2000/05/09 19:53:44 mlemos
30 * Merged with the branch Manuel_Lemos_fixes.
32 * Revision 1.1.2.1 1998/10/12 01:32:38 mlemos
33 * Initial revision adapted from Ian sources.
40 ** Include necessary headers.
41 **/
42 #include "include/classdefs.h"
45 ** Object instance data. Every object
46 ** created from this class has this
47 ** data.
48 **/
49 typedef struct {
50 struct MsgPort *ad_Port; /* Host message port. */
51 UBYTE *ad_HostName; /* Host name. */
52 UBYTE *ad_FileExt; /* File extention. */
53 ULONG ad_PendCnt; /* Messages still un-replied. */
54 REXXCOMMAND *ad_Commands; /* Host command list. */
55 struct RDArgs *ad_DOSParser; /* ReadArgs() parser. */
56 } AD;
59 ** Class data.
60 **/
61 typedef struct {
62 struct Library *RexxSysLibraryBase;
63 } CD;
65 #define RexxSysBase ((CD *)cl->cl_UserData)->RexxSysLibraryBase
68 ** Duplicate a string.
69 **/
70 STATIC UBYTE *DupStr( AD *ad, UBYTE *str )
72 UBYTE *dup = BGUI_AllocPoolMem( strlen( str ) + 1 );
75 ** Allocation OK?
76 **/
77 if ( dup )
79 ** Copy the string.
80 **/
81 strcpy( dup, str );
83 return( dup );
87 ** Reply a rexx command.
88 **/
89 STATIC VOID ReplyRexxCommand(Class *cl, struct RexxMsg *rxm, LONG prim, LONG sec, UBYTE *res )
91 UBYTE buf[ 16 ];
94 ** Result wanted?
95 **/
96 if ( rxm->rm_Action & RXFF_RESULT ) {
98 ** Primary result?
99 **/
100 if ( ! prim ) {
102 ** We setup the secondary result to
103 ** the result string when one was passed.
105 sec = res ? ( LONG )CreateArgstring( res, strlen( res )) : 0L;
106 } else {
108 ** Primary result bigger than 0?
110 if ( prim > 0 ) {
112 ** Setup the result field
113 ** to point to a string containing
114 ** the secondary result number.
116 sprintf( buf, "%ld", sec );
117 res = buf;
118 } else {
120 ** Negate primary result and
121 ** setup the result field to
122 ** the secondary result.
124 prim = -prim;
125 res = ( UBYTE * )sec;
129 ** Setup ARexx it's "RC2" variable to
130 ** the result.
132 SetRexxVar( rxm, "RC2", res, strlen( res ));
135 ** Clear secondary result.
137 sec = 0;
139 } else if ( prim < 0 )
141 ** Negate primary result.
143 prim = -prim;
146 ** Setup result fields.
148 rxm->rm_Result1 = prim;
149 rxm->rm_Result2 = sec;
152 ** Reply the RexxMsg.
154 ReplyMsg(( struct Message * )rxm );
158 ** Free a RexxMsg command.
160 STATIC VOID FreeRexxCommand(Class *cl, struct RexxMsg *rxm )
163 ** Delete the result Argstring.
165 if ( ! rxm->rm_Result1 && rxm->rm_Result2 )
166 DeleteArgstring(( UBYTE * )rxm->rm_Result2 );
169 ** Close input handle.
171 if ( rxm->rm_Stdin && rxm->rm_Stdin != Input()) {
173 ** If the output handle is the
174 ** same as the input handle we
175 ** can safely clear it.
177 if ( rxm->rm_Stdout == rxm->rm_Stdin )
178 rxm->rm_Stdout = NULL;
179 Close( rxm->rm_Stdin );
180 rxm->rm_Stdin = NULL;
184 ** Close output handle if it is not
185 ** the same as Stdin.
187 if ( rxm->rm_Stdout && rxm->rm_Stdout != Output()) {
188 Close( rxm->rm_Stdout );
189 rxm->rm_Stdout = NULL;
193 ** Delete the command Argstring.
195 DeleteArgstring(( UBYTE * )ARG0( rxm ));
197 ** Delete the message itself.
199 DeleteRexxMsg( rxm );
203 ** Create a RexxMsg command.
205 STATIC struct RexxMsg *CreateRexxCommand(Class *cl, AD *ad, UBYTE *comname, BPTR handle )
207 struct RexxMsg *rxm;
210 ** Create the RexxMsg.
212 if ( rxm = CreateRexxMsg( ad->ad_Port, ad->ad_FileExt, ad->ad_HostName )) {
214 ** Create the Argstring.
216 if ( rxm->rm_Args[ 0 ] = CreateArgstring( comname, strlen( comname ))) {
218 ** Setup action flags.
220 rxm->rm_Action = RXCOMM | RXFF_RESULT;
222 ** Setup file handles.
224 rxm->rm_Stdin = rxm->rm_Stdout = handle;
225 return( rxm );
228 ** Argstring creation failed.
230 DeleteRexxMsg( rxm );
232 return( NULL );
236 ** Send a RexxMsg command to the
237 ** ARexx server.
239 STATIC struct RexxMsg *CommandToRexx( AD *ad, struct RexxMsg *rxm )
241 struct MsgPort *rxp;
244 ** Try to find the "REXX"
245 ** message port.
247 Forbid();
249 if ( ! ( rxp = FindPort( RXSDIR ))) {
251 ** Oops. ARexx server
252 ** not active.
254 Permit();
255 return( NULL );
259 ** Send off the message.
261 PutMsg( rxp, &rxm->rm_Node );
263 Permit();
266 ** Increase pending counter.
268 ad->ad_PendCnt++;
270 return( rxm );
274 ** Send a command to the ARexx server.
276 STATIC struct RexxMsg *SendRexxCommand(Class *cl, AD *ad, UBYTE *comname, BPTR handle)
278 struct RexxMsg *rxm;
281 ** Create a RexxMsg command and
282 ** send it off to the ARexx server.
284 if (rxm = CreateRexxCommand(cl, ad, comname, handle))
285 return CommandToRexx(ad, rxm);
287 return NULL;
290 STATIC REXXCOMMAND *FindRXCommand( AD *ad, UBYTE *comname, UWORD len )
292 REXXCOMMAND *rc = ad->ad_Commands;
294 while ( rc->rc_Func ) {
295 if ( ! strnicmp( comname, rc->rc_Name, len ) && isspace( comname[ strlen( rc->rc_Name ) ] ))
296 return( rc );
297 rc++;
300 return( NULL );
304 ** Execute a command.
306 STATIC VOID DoRXCommand(Class *cl, AD *ad, struct RexxMsg *rxm )
308 struct RexxMsg *rm;
309 REXXCOMMAND *rco;
310 REXXARGS *ra;
311 UBYTE *comname, *args, *tmp, *result = NULL;
312 LONG rc = 20, rc2 = 0;
313 UWORD numargs = 0, len = 0;
316 ** Allocate memory for the command
317 ** name and it's argument string.
319 if ( ! ( comname = ( UBYTE * )BGUI_AllocPoolMem( strlen(( UBYTE * )ARG0( rxm )) + 2 ))) {
320 rc2 = ERROR_NO_FREE_STORE;
321 return;
325 ** Copy command name and argument string.
327 strcpy( comname, ( UBYTE * )ARG0( rxm ));
330 ** ReadArgs() requires the argument
331 ** string to end with a newline.
333 strcat( comname, "\n" );
336 ** Find the length of the command
337 ** the start of the arguments.
339 args = comname;
340 while ( isspace( *args )) args++;
341 tmp = args;
342 while ( ! isspace( *args )) { len++; args++; }
345 ** Find the command.
347 if ( rco = FindRXCommand( ad, tmp, len )) {
349 ** Allocate REXXARGS structure.
351 if ( ra = ( REXXARGS * )BGUI_AllocPoolMem( sizeof( REXXARGS ))) {
353 ** Count number of expected args.
355 if ( rco->rc_ArgTemplate ) {
356 tmp = rco->rc_ArgTemplate;
357 while ( *tmp != '\n' ) {
358 if ( *tmp++ == ',' ) numargs++;
360 numargs++;
362 ** Allocate arg array.
364 if ( ra->ra_ArgList = ( ULONG * )BGUI_AllocPoolMem( numargs * sizeof( ULONG ))) {
366 ** Setup RDArgs.
368 ad->ad_DOSParser->RDA_Source.CS_Buffer = args;
369 ad->ad_DOSParser->RDA_Source.CS_Length = strlen( args );
370 ad->ad_DOSParser->RDA_Source.CS_CurChr = 0;
371 ad->ad_DOSParser->RDA_DAList = NULL;
372 ad->ad_DOSParser->RDA_Buffer = NULL;
374 ** Parse args.
376 if ( ReadArgs( rco->rc_ArgTemplate, (LONG *)ra->ra_ArgList, ad->ad_DOSParser )) {
378 ** Call the REXX routine.
380 ( rco->rc_Func )( ra, rxm );
382 rc = ra->ra_RC;
383 rc2 = ra->ra_RC2;
384 result = ra->ra_Result;
386 FreeArgs( ad->ad_DOSParser );
387 } else {
388 rc = 10;
389 rc2 = IoErr();
391 BGUI_FreePoolMem( ra->ra_ArgList );
392 } else
393 rc2 = ERROR_NO_FREE_STORE;
394 } else {
396 ** No args.
398 ( rco->rc_Func )( ra, rxm );
400 rc = ra->ra_RC;
401 rc2 = ra->ra_RC2;
402 result = ra->ra_Result;
404 BGUI_FreePoolMem( ra );
405 } else
406 rc2 = ERROR_NO_FREE_STORE;
407 } else {
409 ** Not found in our list?
410 ** Maybe it's a script.
412 if ( rm = CreateRexxCommand(cl, ad, ( UBYTE * )ARG0( rxm ), NULL )) {
414 ** Save original message.
416 rm->rm_Args[ 15 ] = ( STRPTR )rxm;
418 ** Let the REXX server see what
419 ** it can do with this.
421 if ( ! CommandToRexx( ad, rm ))
422 rc2 = ERROR_NOT_IMPLEMENTED;
423 } else
424 rc2 = ERROR_NO_FREE_STORE;
426 goto byeBye;
429 ReplyRexxCommand(cl, rxm, rc, rc2, result );
431 byeBye:
433 BGUI_FreePoolMem( comname );
436 /// OM_NEW
437 METHOD(ARexxClassNew, struct opSet *,ops)
439 struct TagItem *attr = ops->ops_AttrList;
440 struct MsgPort *mp;
441 AD *ad;
442 ULONG rc, *ecode, err, ext = 1;
443 UBYTE unique_name[80], *tmp;
446 * Let the superclass set us up...
448 if (rc = DoSuperMethodA(cl, obj, (Msg)ops))
451 * Get the instance data.
453 ad = INST_DATA(cl, rc);
455 #ifdef POOLS
457 * Create a memory pool.
459 if (ad->ad_MemPool = LibCreatePool(MEMF_PUBLIC | MEMF_CLEAR, 4096, 4096))
461 #endif
463 * Create port if a
464 * host name is supplied.
466 if (ad->ad_HostName = (UBYTE *)GetTagData(AC_HostName, NULL, attr))
469 * Name valid?
471 if (*ad->ad_HostName)
474 * Make the name unique.
476 Forbid();
477 do {
478 sprintf(unique_name, "%s.%ld", ad->ad_HostName, ext++);
479 } while ((mp = FindPort(unique_name)) && ext <= 99);
480 Permit();
483 * Name unique?
485 if (!mp)
488 * Copy the name.
490 if (ad->ad_HostName = DupStr(ad, unique_name))
493 * Uppercase it.
495 tmp = ad->ad_HostName;
496 do {
497 *tmp = toupper(*tmp);
498 } while (*tmp++);
501 * Create the port.
503 if (ad->ad_Port = CreateMsgPort())
506 * Initialize and add the port.
508 ad->ad_Port->mp_Node.ln_Name = ad->ad_HostName;
509 ad->ad_Port->mp_Node.ln_Pri = 0;
510 AddPort(ad->ad_Port);
511 } else err = RXERR_OUT_OF_MEMORY;
512 } else err = RXERR_OUT_OF_MEMORY;
513 } else err = RXERR_PORT_ALREADY_EXISTS;
514 } else err = RXERR_NO_PORT_NAME;
515 } else err = RXERR_NO_PORT_NAME;
518 * Do we have a port now?
520 if (ad->ad_Port)
523 * Find the commandlist.
525 if (ad->ad_Commands = (REXXCOMMAND *)GetTagData(AC_CommandList, NULL, attr))
528 * Setup the AmigaDOS parser.
530 if (ad->ad_DOSParser = (struct RDArgs *)AllocDosObject(DOS_RDARGS, NULL))
532 ad->ad_DOSParser->RDA_Flags = RDAF_NOPROMPT;
534 * Obtain file extention.
536 ad->ad_FileExt = (UBYTE *)GetTagData(AC_FileExtention, (ULONG)"rexx", attr);
538 return rc;
540 } else err = RXERR_OUT_OF_MEMORY;
541 } else err = RXERR_NO_COMMAND_LIST;
543 #ifdef POOLS
544 } else err = RXERR_OUT_OF_MEMORY;
545 #endif
547 * See if we got error storage.
549 ecode = (ULONG *)GetTagData(AC_ErrorCode, NULL, attr);
550 if (ecode) *ecode = err;
553 * Bliep error...bliep....
555 CoerceMethod(cl, (Object *)rc, OM_DISPOSE);
557 return 0;
559 METHOD_END
561 /// OM_DISPOSE
562 METHOD(ARexxClassDispose, Msg, msg)
564 AD *ad = ( AD * )INST_DATA( cl, obj );
565 struct RexxMsg *rxm;
568 * Do we have a port?
570 if (ad->ad_Port)
573 * Remove the port from the public list
575 RemPort(ad->ad_Port);
577 * Wait for and handle all messages still pending.
579 while (ad->ad_PendCnt)
582 * Wait for a message.
584 WaitPort(ad->ad_Port);
586 * Get messages.
588 while (rxm = (struct RexxMsg *)GetMsg(ad->ad_Port))
591 * Replied message?
593 if (rxm->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
596 * Free the message and decrease the
597 * pending counter.
599 FreeRexxCommand(cl, rxm);
600 ad->ad_PendCnt--;
602 else
605 * Tell'm we're getting out of here.
607 ReplyRexxCommand(cl, rxm, -20, (LONG)"Host object closing down", NULL);
612 * In case there are no messages pending we still
613 * need to reply all that is waiting at the port.
615 while (rxm = (struct RexxMsg *)GetMsg(ad->ad_Port))
616 ReplyRexxCommand(cl, rxm, -20, (LONG)"Host object closing down", NULL);
619 * Delete the port.
621 DeleteMsgPort(ad->ad_Port);
625 * Delete the AmigaDOS parser.
627 if (ad->ad_DOSParser)
628 FreeDosObject(DOS_RDARGS, ad->ad_DOSParser);
631 * Delete the port name.
633 if (ad->ad_HostName)
634 BGUI_FreePoolMem(ad->ad_HostName);
636 #ifdef POOLS
638 * Free the pool.
640 LibDeletePool(ad->ad_MemPool);
641 #endif
644 * Let the superclass do the rest.
646 return DoSuperMethodA(cl, obj, msg);
648 METHOD_END
650 /// OM_GET
651 METHOD(ARexxClassGet, struct opGet *, opg)
653 AD *ad = INST_DATA(cl, obj);
654 ULONG rc = 1;
657 ** What do they want?
659 switch (opg->opg_AttrID)
661 case AREXX_HostName:
662 *(opg->opg_Storage) = (ULONG)ad->ad_HostName;
663 break;
665 case AREXX_SignalMask:
666 *(opg->opg_Storage) = (1 << ad->ad_Port->mp_SigBit);
667 break;
669 default:
670 rc = DoSuperMethodA(cl, obj, (Msg)opg);
671 break;
673 return rc;
675 METHOD_END
677 /// AREXXM_EXECUTE
678 METHOD(ARexxClassExecute, struct acmExecute *, acme)
680 AD *ad = INST_DATA( cl, obj );
681 REXXCOMMAND *rco;
682 REXXARGS *ra;
683 struct RexxMsg *rxm;
684 UBYTE *args, *tmp, *result = NULL, *com;
685 UWORD numargs = 0, len = 0;
686 ULONG r = 20, r2;
689 ** Allocate a private copy of the command string.
691 if ( com = ( UBYTE * )BGUI_AllocPoolMem( strlen( acme->acme_CommandString ) + 2 )) {
693 ** Make a copy terminated with a newline.
695 strcpy( com, acme->acme_CommandString );
696 strcat( com, "\n" );
698 ** Find the length of the command
699 ** and the start of the arguments.
701 args = com;
702 while ( isspace( *args )) args++;
703 tmp = args;
704 while ( ! isspace( *args )) { len++; args++; }
706 ** Look up the command.
708 if ( rco = FindRXCommand( ad, tmp, len )) {
710 ** Allocate a REXXARGS structure.
712 if ( ra = ( REXXARGS * )BGUI_AllocPoolMem( sizeof( REXXARGS ))) {
714 ** Args expected?
716 if ( rco->rc_ArgTemplate ) {
718 ** Count the expected number of arguments.
720 tmp = rco->rc_ArgTemplate;
721 while ( *tmp != '\n' ) {
722 if ( *tmp++ != ',' ) numargs++;
724 numargs++;
726 ** Allocate space to parse the args.
728 if ( ra->ra_ArgList = ( ULONG * )BGUI_AllocPoolMem( numargs * sizeof( ULONG ))) {
730 ** Setup the parser.
732 ad->ad_DOSParser->RDA_Source.CS_Buffer = args;
733 ad->ad_DOSParser->RDA_Source.CS_Length = strlen( args );
734 ad->ad_DOSParser->RDA_Source.CS_CurChr = 0;
735 ad->ad_DOSParser->RDA_DAList = NULL;
736 ad->ad_DOSParser->RDA_Buffer = NULL;
738 ** Parse the args.
740 if ( ReadArgs( rco->rc_ArgTemplate, (LONG *)ra->ra_ArgList, ad->ad_DOSParser )) {
742 ** Run command.
744 ( rco->rc_Func )( ra, NULL );
746 ** Store results.
748 r = ra->ra_RC;
749 r2 = ra->ra_RC2;
750 result = ra->ra_Result;
751 FreeArgs( ad->ad_DOSParser );
752 } else {
753 r = 10;
754 r2 = IoErr();
757 ** Deallocate arg list.
759 BGUI_FreePoolMem( ra->ra_ArgList );
760 } else
761 r2 = ERROR_NO_FREE_STORE;
762 } else {
764 ** Run command.
766 ( rco->rc_Func )( ra, NULL );
768 ** Store results.
770 r = ra->ra_RC;
771 r2 = ra->ra_RC2;
772 result = ra->ra_Result;
775 ** Deallocate the REXXARGS structure.
777 BGUI_FreePoolMem( ra );
778 } else
779 r2 = ERROR_NO_FREE_STORE;
781 ** When not passed to the rexx server
782 ** we must close the given IO handle
783 ** ourselves.
785 if ( acme->acme_IO ) Close( acme->acme_IO );
786 } else {
788 ** We do not send the new-line to
789 ** the ARexx server.
791 com[ strlen( com ) - 1 ] = '\0';
793 ** Unknown commands are shipped
794 ** off to the REXX server.
796 if ( rxm = CreateRexxCommand(cl, ad, com, acme->acme_IO )) {
797 if ( ! CommandToRexx( ad, rxm ))
798 r2 = ERROR_NOT_IMPLEMENTED;
799 else
800 r = r2 = 0L;
801 } else
802 r2 = ERROR_NO_FREE_STORE;
805 ** Deallocate the command copy.
807 BGUI_FreePoolMem( com );
808 } else
809 r2 = ERROR_NO_FREE_STORE;
812 ** Put the results into their
813 ** storage spaces.
815 if ( acme->acme_RC ) *( acme->acme_RC ) = r;
816 if ( acme->acme_RC2 ) *( acme->acme_RC2 ) = r2;
817 if ( acme->acme_Result ) *( acme->acme_Result ) = result;
819 return( 1L );
821 METHOD_END
823 /// AREXXM_HANDLE_EVENT
824 METHOD(ARexxClassHandleEvent, Msg, msg)
826 struct RexxMsg *rxm, *org;
827 AD *ad = INST_DATA(cl, obj);
828 ULONG rc = 1;
831 * Get the messages from the port.
833 while (rxm = (struct RexxMsg *)GetMsg(ad->ad_Port))
836 * A Rexx command?
838 if ((rxm->rm_Action & RXCODEMASK) != RXCOMM)
839 ReplyMsg((struct Message *)rxm);
840 else if (rxm->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
843 * Reply'd message. See if it was started
844 * as a script.
846 if (org = (struct RexxMsg *)rxm->rm_Args[15])
848 if (rxm->rm_Result1)
849 ReplyRexxCommand(cl, org, 20, ERROR_NOT_IMPLEMENTED, NULL);
850 else
851 ReplyRexxCommand(cl, org, 0, 0, (UBYTE *)rxm->rm_Result2);
854 * Free the message and decrease the pending counter.
856 FreeRexxCommand(cl, rxm);
857 ad->ad_PendCnt--;
859 else if (ARG0(rxm))
861 * Execute message.
863 DoRXCommand(cl, ad, rxm);
864 else
865 ReplyMsg((struct Message *)rxm);
867 return rc;
869 METHOD_END
873 * Class function table.
875 STATIC DPFUNC ClassFunc[] = {
876 OM_NEW, (FUNCPTR)ARexxClassNew,
877 OM_DISPOSE, (FUNCPTR)ARexxClassDispose,
878 OM_GET, (FUNCPTR)ARexxClassGet,
879 AREXXM_HANDLE_EVENT, (FUNCPTR)ARexxClassHandleEvent,
880 AREXXM_EXECUTE, (FUNCPTR)ARexxClassExecute,
881 DF_END
884 METHOD(ARexxClassMethodNew, Msg, msg)
886 return((ULONG)((((CD *)cl->cl_UserData)->RexxSysLibraryBase=OpenLibrary("rexxsyslib.library",36L))!=NULL));
888 METHOD_END
890 METHOD(ARexxClassMethodDispose, Msg, msg)
892 CD *class_data=(CD *)cl->cl_UserData;
894 if(class_data->RexxSysLibraryBase)
896 CloseLibrary(class_data->RexxSysLibraryBase);
897 class_data->RexxSysLibraryBase=NULL;
899 return 1;
901 METHOD_END
904 * Class methods function table.
906 STATIC DPFUNC ClassMethods[] = {
907 OM_NEW, (FUNCPTR)ARexxClassMethodNew,
908 OM_DISPOSE, (FUNCPTR)ARexxClassMethodDispose,
909 DF_END
913 * Initialize the class.
915 makeproto Class *InitArexxClass(void)
917 return(BGUI_MakeClass(CLASS_DFTable, ClassFunc,
918 CLASS_ObjectSize, sizeof(AD),
919 CLASS_ClassSize, sizeof(CD),
920 CLASS_ClassDFTable, ClassMethods,
921 TAG_DONE));