home *** CD-ROM | disk | FTP | other *** search
- /*
- * HRexx V0.9
- *
- * einfaches ARexx-Interface für Amiga
- * Achtung der Code ist NICHT reentrant
- *
- * Date Modification by
- * 06.01.90 created D. Heckmman
- * 22.02.90 Vergessen Printf entfernt D. Heckmann
- * BefehlsErkennung bei RexxMessageHandler
- * korrigiert, wenn befehl ohne Argumente kam,
- * wurde er nicht erkannt.
- * 01.08.90 angepasst an ANSI-C D. Heckmann
- * OpenRexx gibt die Maske für Wait zurück
- * GetRexxPort eingebaut.
- * 08.09.90 ModifyRepCount eingebaut, D. Heckmann
- * 09.09.90 wartet nicht mehr auf NONRET Messages !! D. Heckmann
- * 22.11.91 An DICE angepasst (includes eingebaut) D. Heckmann
- * fehlende Protos korrigiert ...
- * Function Pointersalat endgültig ok (Hoffentlich)
- */
-
- /*
- * Danke an die Authoren von MinRexx.
- * Das Listing von MinRexx war beim erstellen dieses ARexxInterfaces
- * sehr hilfreich. (Der Ausdruck lag immer griffbereit neben mir.)
- * MinRexx befindet sich (gezoot) auf der ARexx Disk, und normal
- * auf der FishDisk 188.
- */
-
- #define COMPILING_HREXX
- #define HREXX
-
- #define RXSDIR "REXX"
- #define ERROR_CODE long
- #define SUCCES long
-
- #ifndef _DCC
- #define __stkargs
- #endif
-
- #include "hrexx.h"
- #include <string.h>
- #include <ctype.h>
- #include <exec/ports.h>
- #include <clib/exec_protos.h>
- #include <clib/alib_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/rexxsyslib_protos.h>
- #include <pragmas/exec_pragmas.h>
- #include <pragmas/rexxsyslib_pragmas.h>
- #include <pragmas/dos_pragmas.h>
-
- #include <rexx/rexxio.h>
- #include <rexx/errors.h>
- #include <rexx/storage.h>
- #include "rexx.h"
-
- #include <stdio.h>
-
- Prototype ULONG OpenRexx (char *, const char *, __stkargs void (*do_res)(struct RexxMsg *), BPTR, BPTR);
- Prototype BOOL CloseRexx (void);
- Prototype long LastRexxError (void);
- Prototype struct RexxMsg * BuildRexxMsg (const char *, const long, char *, ...);
- Prototype BOOL RemoveRexxMsg (struct RexxMsg *);
- Prototype BOOL PutRexxMsg (char *, struct RexxMsg *);
- Prototype struct RexxMsg * GetRexxMsg (void);
- Prototype struct RexxMsg * FetchRexxMsg (void);
- Prototype BOOL ReplyRexxMsg (struct RexxMsg *, long, char *);
- Prototype long SyncRexxCommand (const char *, const char *, char *, long, char *, ...);
- Prototype __stkargs void RexxMessageHandler (struct RexxMsg *);
- Prototype void * ChangeProcessMessage (__stkargs void (*new_func)(struct RexxMsg *));
- Prototype struct RexxCommand * SetRexxCommandTable (struct RexxCommand *);
- Prototype long ModifyRepCount (long);
- Prototype BOOL AttempCloseRexx (void);
-
- extern struct DosLibrary * DOSBase;
-
- /*
- * Diesen ErrorCode "I'm Gone" habe ich direkt von MinRexx übernommen.
- * Er ist genausogut wie jeder andere, und auf diese Art wird das
- * Ganze etwas einheitlicher.
- */
- #define RERROR_IMGONE (100)
-
- /*
- * Library Pointer. Enthält den Zeiger auf die LibraryBase.
- * Ist er NULL, so sind alle lokalen globalen Variablen diese Moduls
- * ungültig. Der Zeiger wird mit OpenRexx geholt, und sollte nie
- * vom Klienten geändert werden. Beim Ordnungsgemäßen verlassen
- * (mit CloseRexx) wird er wieder auf NULL gesetzt.
- * So ist das Module zwar nicht PURE, kann aber, wenn es nur einmal
- * zur selben Zeit läuft Resident gemacht werden.
- * Eine komplett lokale Version ist geplant.
- */
- struct RxsLib *RexxSysBase=0;
-
- /*
- * Dies ist ein Zeiger auf den eigenen RexxPort, er wird von
- * der OpenRexx Routine gesetzt.
- */
- static struct MsgPort *rexx_port;
-
- /*
- * Dieser Zähler enthält die Menge der abgesandten Messages, die
- * noch beantwortet werden müßen.
- */
-
- static long outstanding_replies;
-
- /*
- * Dieser Pointer enthält einen Zeiger auf die Default Extension
- * die bei einem Rexx aufruf übergeben werden soll.
- */
- static const char *default_extension; /*+++*/
-
- /*
- * error enthält den letzen FehlerCode
- * negative Werte sind HRexxinterne FehlerCodes.
- */
- static long error;
-
- /*
- * process_message ist die Funktion die von myrexx zur internen
- * Verarbeitung von ankommenden Messages verwendet wird während es mit
- * SyncRexxCommand auf eine AntwortMessage wartet.
- * Sollte dies Funktion eingesetzt werden, so muß sie die Messages
- * die sie übergeben bekommt selbst beantworten.
- */
- static __stkargs void (*process_message)(struct RexxMsg * rmsg);
-
- /*
- * Zeiger auf die Standard Handle (in && Out) die bei einem
- * ArexxAufruf übergeben werden sollen.
- * z.B. Say und Arg greifen auf diese StandardAmigaFileHandles
- * zurück.
- */
- static BPTR std_input,std_output;
-
- /*
- * Command List ist ein Zeiger auf Feld von RexxCommandStrukturen.
- * In dieser Struktur steht der FunktionsName und ein Zeiger auf die
- * Funktion. Kommt einen Message zum internen RexxMessageHandler,
- * so wird die Liste nach einer Funktion des gegebenen Namens und
- * springt die Funktion an.
- * Der letzte Eintrag der Tabelle muß als Namen einen NullZeiger
- * beinhalten.
- * Die Funktion wird mit folgenden Parametern auf gerufen:
- * ret=func(arg0,rexx_mess);
- * arg0 ist ein Zeiger auf den StringRest der nach dem Kommando folgt.
- * rexx_mess ist ein Zeiger auf die RexxStruktur.
- * Gibt die Funktion TRUE als RET zurück, so übernimmt der Handler
- * das beantworten der Message.
- */
- static struct RexxCommand *command_table;
-
-
-
-
- /*********************************************************************/
- /* Die Funktion OpenRexx öffnet, wenn möglich einen RexxPort. */
- /*********************************************************************/
-
- ULONG OpenRexx(char * name,const char *ext, __stkargs void (*do_res)(struct RexxMsg *rmsg),BPTR in, BPTR out)
- /*
- * OpenRexx initialisiert die ARexxumgebung. Dafür wird, wenn benötigt
- * Arexxlibrary geöffnet, ein Port initialisiert, die Defaultextension
- * festgelegt und die std Ein- und Ausgabekanäle bestimmt.
- *
- * --> name Name des ARexxPorts den unser Programm bekommt.
- * Existiert ein solcher Port bereits wird der FehlerCode
- * ERROR_PORT_ALLREADY_EXISTS zurückgegeben
- * --> ext Zeiger auf die extension, wenn NULL dan .REXX
- * --> do_res Zeiger auf die Funktion zum Message handling.
- * Wird aufgerufen wenn während der Arbeit ein RexxMsg anfällt
- * --> in,out std input/output handle
- * <-- RESLUT SigBit Success FALSE wenn nicht geöffnet
- */
- {
- /* Portname vorhanden ? */
- if (name==0 || strlen(name)==0)
- {
- error=RERROR_INVALID_PORT_NAME;
- return(0);
- }
-
- /* Prüfen ob ARexx schon geöffnet ist, wenn ja, */
- /* dann keinen Port öffnen */
- if (RexxSysBase)
- {
- error=RERROR_AREXX_ALLREADY_OPEN;
- return(0);
- }
-
- /* ARexxLib öffnen */
- if ((RexxSysBase=(struct RxsLib *)OpenLibrary("rexxsyslib.library",0))==0)
- {
- error=RERROR_NO_AREXX;
- return(0);
- }
-
- /* Prüft ob ein Port mit dem selben Namen existiert, */
- /* wenn ja bricht das Programm mit einem Fehler ab. */
- Forbid();
- if (FindPort(name))
- {
- Permit();
- CloseLibrary((struct Library *)RexxSysBase);
- RexxSysBase=0;
- error=RERROR_PORT_ALLREADY_EXISTS;
- return(0);
- }
-
- /* Port kreieren, wenn möglich */
- if ((rexx_port=CreatePort(name,0))==0)
- {
- /* konnte keinen Port aufmachen */
- Permit();
- error=RERROR_NO_PORT;
- CloseLibrary((struct Library *)RexxSysBase);
- RexxSysBase=0;
- return(0);
- }
- Permit();
-
- /* E/A-Kanäle festlegen */
- if (in<0) std_input=Input();
- else std_input=in;
- if (out<0) std_output=Output();
- else std_output=out;
-
- /* extension zuweisen */
- default_extension=ext;
-
- /* ResultFunktions Pointer setzen */
- process_message=do_res;
-
- /* keine Messages */
- outstanding_replies=0;
-
- /* FunktionTable löschen */
- command_table=0;
-
- /* Zeiger auf den MessagePort zurückgeben */
- return ((ULONG)1L<<rexx_port->mp_SigBit);
- }
-
- BOOL AttempCloseRexx(void)
- /*
- AttempCloseRexx
- probiert den ARexxPort zu schliessen (funktioniert nur, wenn
- OutstandingReplies==0 ist), kann das RexxSystem geschlossen
- werden kommt TRUE zurück, sonst False
- */
- {
- if (outstanding_replies>0)
- return(FALSE);
- return(CloseRexx());
- }
-
- /******************************************************************/
- /* beantwortet alle anstehenden Messages, mit RXRERRORIMGONE */
- /* wartet auf alle noch zu beantwortenden Messages */
- /* schließt den Port */
- /* schließt die ArexxSysBase */
- /******************************************************************/
-
- BOOL CloseRexx(void)
- {
- struct RexxMsg *rmsg;
-
- /* prüft ob es übehaupt etwas zu schließen gibt */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(FALSE);
- }
-
- /*
- * Achtung diese Funktion prüft nur, ob alle abgeschickten
- * Messages eine Antwort bekommen haben. Nicht aber ob alle
- * angekommenen Messages beantwortet wurden.
- * Antworten wandern ins NIL
- */
- while (outstanding_replies)
- {
- /* Message vom Port holen */
- while ((rmsg = (struct RexxMsg *)GetMsg (rexx_port)) == 0)
- WaitPort ((struct MsgPort *)rexx_port);
-
- /* gesuchte antwort ? */
- if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
- {
- /* erwartete antwort, message freigeben */
- RemoveRexxMsg (rmsg);
-
- outstanding_replies --;
- } else
- {
- /* alle jetzt ankommenden Kommandos dankent ablehnen
- * sollte es eine no-return message sein, den Speicher
- * freigeben und weitermachen, sonst mit RXRERRORIMGONE
- * beantworten
- */
- if (rmsg->rm_Action & RXFF_NONRET)
- {
- RemoveRexxMsg (rmsg);
- } else
- {
- rmsg->rm_Result2 = 0;
- rmsg->rm_Result1 = RERROR_IMGONE;
-
- ReplyMsg((struct Message *) rmsg);
- }
- }
- } /* while outstanding_replies */
-
- /* Port vom System löschen */
- DeletePort (rexx_port);
-
- /* ArexxLib schließen */
- CloseLibrary ((struct Library *)RexxSysBase);
- RexxSysBase = 0;
-
- return (TRUE);
- }
-
-
- /********************************************************************/
- /* Mit dieser Funktion kann man den letzten aufegetreten */
- /* FehlerCode festellen */
- /********************************************************************/
- long LastRexxError(void)
- {
- return(error);
- }
-
-
- /****************************************************************/
- /* BuildRexxMsg erstellt eine ARexx Message und füllt */
- /* die Argument slots mit den Parametern */
- /****************************************************************/
- /*
- * Aufruf erfolgt: BuildRexxMsg(com,flags,arg0,arg1,arg2,...,argn)
- * Es dürfen maximal 15 Argumente übergeben werden. Weitere Argumente
- * werden ignoriert. Will man nur 3 Argumente übergeben (arg1-arg3)
- * übergibt man als letztes Argument (arg4) NULL
- * Die Funktion gibt einen Zeiger auf die erstellte Message zurück,
- * im Fehlerfalle NULL.
- */
- struct RexxMsg *BuildRexxMsg
- (
- /*
- * com ist der Name des aufzurufenden Kommandos.
- * Alles Strings (com & args) sind normale mit NULL abgeschloßene
- * C-Strings.
- */
- const char *com,
- /*
- * action dieses Flag wir direkt im Command (action) Field
- * der RexxMessage struktur eingefügt
- */
- const long action,
- /*
- * first_arg is ein Zeiger auf das erste Argument (aufruf der
- * Funktion s.o.
- * Aufgrund der internen Handhabung wird nur der erste Parameter im
- * Funktionskopf angenommen.
- * Die Argumente sind normale 0-terminierte C-Strings
- */
- char *first_arg,
- /*
- * Weitere Argumente:
- */
- ...
- )
- {
- struct RexxMsg *rmsg;
- register i;
- char **args;
-
- /* Rexx geöffnet ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(0);
- }
-
- /* gültiges Kommando ? */
- if (com==0 || *com==0)
- {
- error=RERROR_INVALID_COMMAND_NAME;
- return(0);
- }
-
- /* RexxMessage-Body erstellen */
- if ((rmsg=CreateRexxMsg(rexx_port,default_extension, rexx_port->mp_Node.ln_Name))==0)
- /* konnte keine RexxMessage erstellen */
- {
- error=RERROR_OUT_OF_MEMORY;
- return(0);
- }
-
-
- /* Die Kommandos und Argumente einfügen */
- /* erst das Kommando */
- rmsg->rm_Args[0]=(STRPTR) com;
-
- /*
- * Die Argumente einlesen. Zur einfacheren Verarbeitung generieren
- * wir ein Feld in dem die Argumente stehen, und das man mit einer
- * Schleife abarbeiten kann
- */
- args=&first_arg;
-
- /* Jetzt alle Argumente bis zum ersten NULL argument in die
- Message eintragen.*/
- for (i=1;i<15 && args[i-1];i++)
- rmsg->rm_Args[0]=(STRPTR) args[i-1];
-
- /*
- * Mit der Funktion FillRexxMsg kann man nun die Strings in der
- * Message durch Rexx Argsstrings ersetzen lassen.
- */
- if (!FillRexxMsg(rmsg,i,0))
- {
- /*
- * wahrscheinlich zuwenig mem für die Umwandlung, also
- * ErrorCode setzen, die nicht gebrauchte Message zurückgeben
- * und Abgang
- */
- error=RERROR_OUT_OF_MEMORY;
- DeleteRexxMsg(rmsg);
- return(0);
- }
-
- /* Command feld initialisieren */
- rmsg->rm_Action=action;
-
- return(rmsg);
- }
-
-
- /*****************************************************************/
- /* Dies Funktion gibt den Speicher einer RexxMessage frei. */
- /* Also die Argumente, einen ggf vorhandenen ReturnWert */
- /* und die Message selbst. Aus diesem Grund müßen Felder */
- /* (Argumente und Return Code, wenn sie außerhalb der */
- /* Funktion freigegeben worden sind auf NULL gesetzt werden */
- /*****************************************************************/
- BOOL RemoveRexxMsg
- (
- /* Zeiger auf die zu löschende RexxMessage */
- /*
- * gibt TRUE für Erfolg zurück
- */
- struct RexxMsg *rmsg
- )
- {
- /* Rexx geöffnet ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(FALSE);
- }
-
- /*
- * Als erstes prüfen, ob ein Return String vorhanden ist,
- * wenn ja, dann löschen. Diese Funktion löscht den ReturnString
- * nur dann, wenn in Action ein Result gefordert ist. Und kein
- * Error im Result1 Feld eigetragen ist.
- */
- if ((rmsg->rm_Action&RXFF_RESULT) && rmsg->rm_Result1==0 && rmsg->rm_Result2!=0)
- {
- DeleteArgstring((char *)rmsg->rm_Result2);
- rmsg->rm_Result2=0;
- }
-
- /*
- * Alle übergebenen Argumente mit ClearRexxMsg löschen.
- * Bei dieser Funktion werden alle Argumente die nicht NULL sind
- * als RexxStringPointer interpretiert und diese Strings freigegeben
- */
- ClearRexxMsg(rmsg,16);
-
- /* zum Abschluß noch die eigentliche Message freigeben */
- DeleteRexxMsg(rmsg);
- return(TRUE);
- }
-
-
- /****************************************************************/
- /* PutRexxMsg schickt eine Message an den genannten Port */
- /* un übernimmt die Buchführung über fehlende Antworten */
- /****************************************************************/
- BOOL PutRexxMsg
- (
- /*
- * Port ist der Name des Ziel Ports. Der Name ist NULL beendeter
- * String. Achtung !! kein PortPointer.
- * Ist port NULL so wird die Message an den RexxHostPort geschickt.
- * Da man einen eigenen Namen angeben kann, ist möglich, Messages
- * direkt an andere Rexxfähige Programme zu senden.
- */
- char *port,
- /*
- * rmsg ist ein Zeiger auf gültige, vollstänig initialisierte
- * RexxMessage-Struktur.
- */
- struct RexxMsg *rmsg
- )
- {
- struct MsgPort *msg_port;
-
- /* Rexx opened ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(FALSE);
- }
-
- /* Prüfen ob der standard RexxPort gefragt ist, wenn ja */
- /* dann RXSDIR ("REXX") einsetzen */
- if (port==0)
- port=RXSDIR;
-
- /* Prüfen ob es überhaupt einen PortNamen gibt, wenn nicht
- * Fehler */
- if (*port==0)
- {
- error=RERROR_NO_PORT;
- return(FALSE);
- }
-
- /* Message Port suchen */
- Forbid();
- if ((msg_port=FindPort(port))==0)
- {
- /* gewünschter Port existiert nicht */
- Permit();
- error=RERROR_UNKNOWN_DESTINATION_PORT;
- return(FALSE);
- }
- PutMsg((struct MsgPort *)msg_port,(struct Message *) rmsg);
- Permit();
-
- /* abgeschickte Message merken */
- if ((rmsg->rm_Action & RXFF_NONRET) == 0)
- {
- outstanding_replies ++;
- }
-
- return (TRUE);
- }
-
-
- /****************************************************************/
- /* GetRexxMsg funktioniert GetMsg des Betriebsystems, */
- /* nur das Über die Messages Buchgeführt wird */
- /****************************************************************/
- struct RexxMsg *GetRexxMsg(void)
- /*
- * Die Funktion gibt einen Zeiger auf die Message oder NULL
- * zurück.
- * Ist NULL ein Fehler, so kann das mit LastRexxError festgestellt
- * werden. Sonst bedeutet es einfach, das keine Msg am Port
- * wartet.
- */
- {
- struct RexxMsg *rmsg;
-
- /* Rexx geöffnet ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(0);
- }
- error=0;
-
- /* Message holen */
- if ((rmsg=(struct RexxMsg *)GetMsg(rexx_port))==0)
- /* keine Message am Port also return(0) */
- return(0);
-
- /* Überprüfen ob es eine Antwort auf eine von uns abgeschickte
- * Message ist. Wenn ja die Antwort veruchen.
- * Achtung !! Auch die Rückantwort wird nicht freigegeben
- */
- if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
- outstanding_replies--;
-
- return(rmsg);
- }
-
-
- /****************************************************************/
- /* FetchRexxMsg wartet bis eine Message an unserm */
- /* Port ankommt und gibt diese zurück. */
- /****************************************************************/
- struct RexxMsg *FetchRexxMsg(void)
- /*
- * Die Funktion kehrt mit einem Zeiger auf die vom
- * Port geholte Message zurück.
- */
- {
- struct RexxMsg *rmsg;
-
- /* Rexx geöffnet ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(0);
- }
-
- while ((rmsg=GetRexxMsg())==0)
- WaitPort(rexx_port);
-
- return(rmsg);
- }
-
-
- /****************************************************************/
- /* ReplyRexxMsg setzt den ArexxErrorCode, füllt den */
- /* Returnwert_slot und beantwortet die Message. */
- /* sollte es eine NonReply Message sein, so wird sie */
- /* einfach gelöscht */
- /****************************************************************/
- BOOL ReplyRexxMsg
- /*
- * Im falle eines Fehlers kehrt die Funktion mit FALSE zurück.
- * Nähere Information kann man LastRexxError holen
- */
- (
- /*
- * rmsg ist ein Zeiger auf die zu beantwortende Message
- */
- struct RexxMsg *rmsg,
- /*
- * rexx_error ist ein Langwort, das den ArexxErrorCode enthält.
- * Der Code wird in das Result1 Feld der Message eingetragen.
- */
- long rexx_error,
- /*
- * return_string ist ein String, der als Return wert and den
- * Caller zurückgegeben wird. ReplyRexxMsg generiert aus diesem
- * C-String ein ArexxArgument und füllt dieses in das Result2
- * Feld ein.
- * Ist rexx_error != 0, also ein Fehler aufgetreten, so wird der
- * String ignoriert und das Feld auf NULL gesetz. Soll kein
- * Returnwert zurückgegeben werden ist ein NULL-Pointer zu übergeben.
- */
- char *return_string
- )
- {
- STRPTR rx_string;
-
- /* Rexx geöffnet ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(FALSE);
- }
-
- /* Message übergeben worden ? */
- if (rmsg==0)
- {
- error=RERROR_NO_MSG;
- return(FALSE);
- }
-
- /* Ist es eine NonRet, wenn ja, so wird die Message
- * nicht beantwortet, sondern gelöscht.
- */
- if (rmsg->rm_Action & RXFF_NONRET)
- {
- RemoveRexxMsg(rmsg);
- return(TRUE);
- }
-
- /* ErrorCode eintragen */
- rmsg->rm_Result1=rexx_error;
-
- /*
- * im FehlerFalle Result2 auf NULL setzen, das ist zwar nach
- * der ARexx Dokumentation nicht nötig, aber man weis ja
- * nie mit wem es HRexx zu tun hat.
- */
- if (rexx_error)
- rmsg->rm_Result2=NULL;
- else
- /*
- * Wenn kein Fehler aufgetreten ist und eine ReturnString übergeben
- * wurde und die Message eine Antowrt erwartet, so wird aus dem
- * return_string ein Argument String erstellt und an den Caller
- * zurückgegeben
- */
- if (return_string && (rmsg->rm_Action & RXFF_RESULT))
- {
- rx_string=(STRPTR) CreateArgstring(return_string,strlen(return_string));
- if (rx_string==0)
- {
- /*
- * Falls kein String erstellt werden kann, wird die
- * Funktion mit eine Fehler abgebrochen. In diesem Fall
- * kann man es z.B. damit versuchen, das man keinen
- * return_string übergibt
- */
- error=RERROR_OUT_OF_MEMORY;
- return(FALSE);
- }
- rmsg->rm_Result2=(LONG)rx_string;
- }
-
- /* unsere hübsche Message zurück an den Chef */
- ReplyMsg((struct Message *) rmsg);
- return(TRUE);
- }
-
-
- /**********************************************************************/
- /* SyncRexxCommand sendet ein Kommando, und wartet bis das */
- /* Kommando abgearbeitet ist. Sollten in der Zwischenzeit */
- /* Kommandos an unser Port gehen, wird die Funktion */
- /* process_message mit dem Zeiger auf die Message aufgerufen. */
- /* So ist es möglich, währen eines SyncAufrufes Kommandos zu */
- /* Empfangen. SyncRexxCommand unterstützt einen returncode. */
- /* Dazu muß eine StringBuffer und die Größe des Buffer über- */
- /* geben werden . */
- /* Der aufruf erfolgt: */
- /* SyncRexxCommand(port,com,result,result_len,arg1,arg2,...,argn)*/
- /* Werden nicht alle Argumente genutzt, muß das letzte Argument */
- /* NULL sein. Mehr als 15 Argumente werden ignoriert. */
- /**********************************************************************/
- long SyncRexxCommand
- /*
- * Die Funktion kehrt mit dem ArexxErrorCode oder dem Internen
- * errorcode zurück.
- * 0 für eine erfolgreiche aktion.
- * Kommt es zu einem RexxFehler, so wird der ResultString gelöscht.
- */
- (
- /*
- * port ist der Name des Ports an den das Kommando gesendet werden soll.
- * wird als PortName 0 angegeben, so wird das Kommando an den Rexx-
- * Host geschickt.
- */
- const char *port,
- /*
- * Com ist der String der den KommandoNamen enthält
- */
- const char *com,
- /*
- * result ist ein Pointer auf den StringBuffer in den der
- * ResultString des Kommandos kopiert werden soll. Ist result == NULL
- * oder result_len == NULL so wird die Fukntion als Kommando
- * ohne ReturnWert betrachtet, und die Flags in der RexxMsg
- * entsprechend gesetzt.
- */
- char *result,
- long result_len,
- /*
- * first_arg Zeiger auf den ersten Argument String. Der aufruf Syntax
- * ist oben beschrieben, und Funktioniert wie bei BuildRexxMessage.
- */
- char *first_arg,
- /*
- * weitere args
- */
- ...
- )
- {
- char **args;
- struct RexxMsg *rmsg;
- struct RexxMsg *our_msg;
- long flag;
- register i;
- register char *s;
-
- /* Rexx geöffnet ? */
- if (RexxSysBase==0)
- {
- error=RERROR_AREXX_NOT_OPEN;
- return(-1);
- }
-
- /* wurde ein Kommando übergeben ? */
- if (com==0 || *com==0)
- {
- error=RERROR_INVALID_COMMAND_NAME;
- return(-1);
- }
-
- /* prüfen ob ein Result erwartet wird und die Flags für die
- * Message entprechend vorbereiten
- */
- flag=RXCOMM;
- if (result && result_len) flag|=RXFF_RESULT;
-
- /* Argumente Feld übernehmen */
- args=&first_arg;
- /* Die Message erstellen */
- our_msg=BuildRexxMsg(com,flag,args[0],args[1],args[2],args[3],
- args[4],args[5], args[6],args[7],args[8],args[9],args[10],
- args[10],args[11], args[12],args[13],args[14]);
- /* geklappt ?*/
- if (our_msg==0) return(-1);
-
- /* let's fets und schon schicken wir die Msg ab */
- if (!PutRexxMsg(port,our_msg))
- {
- /* speicher der Message freigeben */
- RemoveRexxMsg(our_msg);
- return(-1);
- }
-
- /* jetzt warten wir bis unsere Message beantwortet zurück kommt */
- do
- {
- rmsg=FetchRexxMsg();
-
- /* unsere Message ? */
- if (rmsg==our_msg) break;
-
- /* eine Antwort auf eine alte Message ? */
- if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
- RemoveRexxMsg(rmsg);
- else
- /*
- * haben wir eine Funktion die für die Bearbeitung
- * ankommender Messages zuständig ist ?
- * wenn ja, dann Funktion anspringen, sonst Message mit
- * Unknown Command zurückgeben
- */
- if (process_message!=0)
- {
- (*process_message)(rmsg);
- }
- else
- ReplyRexxMsg(rmsg,ERR10_030,0);
- } /* auf Antwort warten */
- while (TRUE);
-
- /* error code retten */
- flag=our_msg->rm_Result1;
-
- /* wenn kein error aufgetreten ist und ein Result erwartet wird
- * wird der Result String in den Buffer kopiert
- */
- if (flag==0 && result && result_len)
- {
- /* Zeiger Resultstring holen */
- if (s=(char *)rmsg->rm_Result2)
- {
- for (i=0;i<(result_len-1) && s[i];i++)
- result[i]=s[i];
- result[i]=0;
- if (s[i]!=0)
- {
- /* wenn der Ergebniss string zu lang ist error code setzen
- * zurückgeben und den string mittendrin abbrechen.
- */
- flag=RERROR_STRING_TOO_LONG;
- }
- } else
- *result = 0;
- }
- RemoveRexxMsg(our_msg);
- return(flag);
- }
-
- /****************************************************************/
- /* RexxMessageHandler sucht die FunktionsListe durch, und */
- /* ruft, falls es das Kommando gibt, die dazugehörige */
- /* Funktion auf. Sollte das Kommando nicht existieren */
- /* wird der ARexxFehlerCode Label NotFound zurückgegeben. */
- /****************************************************************/
- __stkargs void RexxMessageHandler (struct RexxMsg *rmsg)
- /*
- * RexxMessageHandler ruft bei ankommenden Messages die in der
- * Funktionliste übergebenen Kommandos auf.
- *
- * --> rmsg Zeiger auf die RexxMessage, die bearbeitet werden soll
- */
- {
- register i;
- register act_com;
- char *s;
-
- /* existier ein CommandTable ? */
- if (command_table==0)
- {
- /* Message mit Unknown Label beantworten */
- ReplyRexxMsg(rmsg,ERR10_030,0);
- return ;
- }
-
-
- /* Zeiger auf den Commando String holen */
- s=(char *)rmsg->rm_Args[0];
-
- /*
- * Kommando liste nach dem Kommando druchsuchen, wenn die Funktion
- * gefunden wird, aufrufen sonst mit UNKNOWN_LABEL beantworten.
- * Aufgrund der Vergleichs Funktion müßen Kommandos, die als Anfang
- * in einem anderen Kommando der Tabelle enthalten sind hinter
- * diesen stehen, das sonst die längeren Kommandos nicht gefunden
- * würden.
- * So muß die Funktion "test" nach der Funktion "testme" stehen.
- * Beim vergleich wird die groß klein Schreibung ignoriert.
- * Strings mit der Länge 0 verwirren die Funktion ebenfalls.
- */
- for (act_com=0;command_table[act_com].Name;act_com++)
- {
- /* String vergleichen */
- for (i=0;(toupper(command_table[act_com].Name[i])==toupper(s[i])) && (s[i]!=0);i++);
- if (command_table[act_com].Name[i]==0)
- {
- /* Skip Spaces in Kommando bis zu argumenten */
- while (s[i]==32) i++;
- /* Funktion aufrufen */
- if (command_table[act_com].Function(s+i,rmsg))
- /* Message beantworten */
- ReplyRexxMsg(rmsg,0,0);
- goto done;
- }
- }
-
- /* Kommando unbekannt */
- ReplyRexxMsg(rmsg,ERR10_030,0);
-
- done:;
- }
-
-
- /****************************************************************/
- /* ChangeProcessMessage ändert den Zeiger der process_ */
- /* message funktion. */
- /****************************************************************/
- void * ChangeProcessMessage(__stkargs void (*new_function)(struct RexxMsg * rmsg))
- /*
- * ChangeProcessMessage ändert die Funktion für das InterneMessagehandling
- *
- * --> new_function Zeiger auf die neue Funktion, bei -1 wird
- * der HRexx interne Handler verwendet
- * <-- RESULT Pointer auf alten hndler
- */
- {
- void (*old_function)(struct RexxMsg * rmsg);
-
- /* alte Funktion zurückgeben */
- old_function=process_message;
-
- /* Internen handler ? */
- if ((long)new_function==-1)
- process_message = RexxMessageHandler;
- else
- process_message = new_function;
-
- if ((long)old_function==(long)RexxMessageHandler)
- old_function=(void (*)(struct RexxMsg *))-1;
-
- return (old_function);
- }
-
- /****************************************************************/
- /* SetRexxCommandTable ändert die interne Kommandotabelle */
- /****************************************************************/
- struct RexxCommand * SetRexxCommandTable
- (
- /*
- * Zeiger auf eine vom Benutzer definierte Kommando Tabelle
- */
- struct RexxCommand *new_com_tab
- /*
- * gibt den Zeiger auf die alte Funktiontabelle zurück.
- */
- )
- {
- struct RexxCommand *old_com_tab;
-
- old_com_tab=command_table;
- command_table=new_com_tab;
-
- /* Ist der FunktionTable != NULL so wird die Handler Funktion
- * auf den internen MessageHandler umgelenkt. Sonst wird der Message
- * Handler Pointer auf NULL gesetzt, wenn er vorher auf den
- * RexxMessageHandler gezeigt hat
- */
- if (command_table!=0)
- {
- ChangeProcessMessage((void *)-1);
- }
- else
- if ((long)process_message==(long)RexxMessageHandler)
- process_message=0;
-
- return(old_com_tab);
- }
-
- /*************************************************************/
- /* ModifyRepCount ändert Anzahl fehlender Messages */
- /*************************************************************/
- long ModifyRepCount(long delta)
- /*
- ModifyRepCount
- ändert den Counter mit den fehlenden Messages um den in
- delta angegebenen Betrag.
- Der alte wert von RepCount wird zurückgegeben
- */
- {
- long old; /* alter wert von outstandig_replies */
-
- old=outstanding_replies; /* alten wert merken */
- outstanding_replies+=delta; /* ändern */
- return(old);
- }
-
-
- #ifdef DEBUG
- /* testing enviroment */
-
- #include <stdio.h>
- hallo(arg)
- char *arg;
- {
- printf("Rexx called hallo with:\"%s\"\n",arg);
- return (TRUE);
- }
-
- struct RexxCommand rcs[]=
- {
- "hallo",(void *)hallo,
- 0,0
- };
-
-
- main(argc,argv)
- long argc;
- char **argv;
- {
- struct RexxMsg *rmsg;
- char result[100];
- long error;
-
- if (OpenRexx("RexxTest","test",0,-1,-1)==0)
- {
- printf("OpenError %ld\n",LastRexxError());
- goto err;
- }
-
- SetRexxCommandTable(rcs);
-
- result[0]=0;
-
- error=SyncRexxCommand(0,"ootest tatara",result,100,0);
- printf("%ld %s\n",error,result);
-
- err:;
- CloseRexx();
- } /* main */
- #endif
-