home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / xdme_1.84_src.lha / XDME / Src / hrexx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-14  |  29.5 KB  |  1,067 lines

  1. /*
  2.  *    $Id: hrexx.c 1.1 1994/08/14 12:30:15 digulla Exp digulla $
  3.  *
  4.  *    einfaches ARexx-Interface für Amiga
  5.  *    Achtung der Code ist NICHT reentrant
  6.  *
  7.  *    Date       Modification                 by
  8.  *    06.01.90   created                    D. Heckmman
  9.  *    22.02.90   Vergessen Printf entfernt            D. Heckmann
  10.  *           BefehlsErkennung bei RexxMessageHandler
  11.  *           korrigiert, wenn befehl ohne Argumente kam,
  12.  *           wurde er nicht erkannt.
  13.  *    01.08.90   angepasst an ANSI-C                D. Heckmann
  14.  *           OpenRexx gibt die Maske für Wait zurück
  15.  *           GetRexxPort eingebaut.
  16.  *    08.09.90   ModifyRepCount eingebaut,            D. Heckmann
  17.  *    09.09.90   wartet nicht mehr auf NONRET Messages !!    D. Heckmann
  18.  *    22.11.91   An DICE angepasst (includes eingebaut)       D. Heckmann
  19.  *           fehlende Protos korrigiert ...
  20.  *           Function Pointersalat endgültig ok (Hoffentlich)
  21.  *    $Log: hrexx.c $
  22.  * Revision 1.1  1994/08/14  12:30:15  digulla
  23.  * Initial revision
  24.  *
  25.  *
  26.  */
  27.  
  28. /*
  29.  *    Danke an die Authoren von MinRexx.
  30.  *    Das Listing von MinRexx war beim erstellen dieses ARexxInterfaces
  31.  *    sehr hilfreich. (Der Ausdruck lag immer griffbereit neben mir.)
  32.  *    MinRexx befindet sich (gezoot) auf der ARexx Disk, und normal
  33.  *    auf der FishDisk 188.
  34.  */
  35.  
  36. #define  COMPILING_HREXX
  37. #define  HREXX
  38.  
  39. #define  RXSDIR "REXX"
  40. #define  ERROR_CODE    long
  41. #define  SUCCES     long
  42.  
  43. #ifndef _DCC
  44. #define __stkargs
  45. #endif
  46.  
  47. #include "hrexx.h"
  48. #include <string.h>
  49. #include <ctype.h>
  50. #include <exec/ports.h>
  51. #include <clib/exec_protos.h>
  52. #include <clib/alib_protos.h>
  53. #include <clib/dos_protos.h>
  54. #include <clib/rexxsyslib_protos.h>
  55. #include <pragmas/exec_pragmas.h>
  56. #include <pragmas/rexxsyslib_pragmas.h>
  57. #include <pragmas/dos_pragmas.h>
  58.  
  59. #include <rexx/rexxio.h>
  60. #include <rexx/errors.h>
  61. #include <rexx/storage.h>
  62. #include "rexx.h"
  63.  
  64. #include <stdio.h>
  65.  
  66. Prototype ULONG            OpenRexx         (char *, const char *, __stkargs void (*do_res)(struct RexxMsg *), BPTR, BPTR);
  67. Prototype BOOL               CloseRexx        (void);
  68. Prototype long               LastRexxError        (void);
  69. Prototype struct RexxMsg     * BuildRexxMsg        (const char *, const long, char *, ...);
  70. Prototype BOOL               RemoveRexxMsg        (struct RexxMsg *);
  71. Prototype BOOL               PutRexxMsg        (char *, struct RexxMsg *);
  72. Prototype struct RexxMsg     * GetRexxMsg        (void);
  73. Prototype struct RexxMsg     * FetchRexxMsg        (void);
  74. Prototype BOOL               ReplyRexxMsg        (struct RexxMsg *, long, char *);
  75. Prototype long               SyncRexxCommand        (const char *, const char *, char *, long, char *, ...);
  76. Prototype __stkargs void       RexxMessageHandler   (struct RexxMsg *);
  77. Prototype void             * ChangeProcessMessage (__stkargs void (*new_func)(struct RexxMsg *));
  78. Prototype struct RexxCommand * SetRexxCommandTable  (struct RexxCommand *);
  79. Prototype long               ModifyRepCount        (long);
  80. Prototype BOOL               AttempCloseRexx        (void);
  81.  
  82. extern struct DosLibrary * DOSBase;
  83.  
  84. /*
  85.  *    Diesen ErrorCode "I'm Gone" habe ich direkt von MinRexx übernommen.
  86.  *    Er ist genausogut wie jeder andere, und auf diese Art wird das
  87.  *    Ganze etwas einheitlicher.
  88.  */
  89. #define  RERROR_IMGONE    (100)
  90.  
  91. /*
  92.  *    Library Pointer. Enthält den Zeiger auf die LibraryBase.
  93.  *    Ist er NULL, so sind alle lokalen globalen Variablen diese Moduls
  94.  *    ungültig. Der Zeiger wird mit OpenRexx geholt, und sollte nie
  95.  *    vom Klienten geändert werden. Beim Ordnungsgemäßen verlassen
  96.  *    (mit CloseRexx) wird er wieder auf NULL gesetzt.
  97.  *    So ist das Module zwar nicht PURE, kann aber, wenn es nur einmal
  98.  *    zur selben Zeit läuft Resident gemacht werden.
  99.  *    Eine komplett lokale Version ist geplant.
  100.  */
  101. struct    RxsLib *RexxSysBase=0;
  102.  
  103. /*
  104.  *    Dies ist ein Zeiger auf den eigenen RexxPort, er wird von
  105.  *    der OpenRexx Routine gesetzt.
  106.  */
  107. static    struct    MsgPort *rexx_port;
  108.  
  109. /*
  110.  *    Dieser Zähler enthält die Menge der abgesandten Messages, die
  111.  *    noch beantwortet werden müßen.
  112.  */
  113.  
  114. static    long    outstanding_replies;
  115.  
  116. /*
  117.  *    Dieser Pointer enthält einen Zeiger auf die Default Extension
  118.  *    die bei einem Rexx aufruf übergeben werden soll.
  119.  */
  120. static    const  char    *default_extension;    /*+++*/
  121.  
  122. /*
  123.  *    error    enthält den letzen FehlerCode
  124.  *    negative Werte sind HRexxinterne FehlerCodes.
  125.  */
  126. static    long    error;
  127.  
  128. /*
  129.  *    process_message  ist die Funktion die von myrexx zur internen
  130.  *    Verarbeitung von ankommenden Messages verwendet wird während es mit
  131.  *    SyncRexxCommand auf eine AntwortMessage wartet.
  132.  *    Sollte dies Funktion eingesetzt werden, so muß sie die Messages
  133.  *    die sie übergeben bekommt selbst beantworten.
  134.  */
  135. static    __stkargs void    (*process_message)(struct RexxMsg * rmsg);
  136.  
  137. /*
  138.  *    Zeiger auf die Standard Handle (in && Out) die bei einem
  139.  *    ArexxAufruf übergeben werden sollen.
  140.  *    z.B. Say und Arg greifen auf diese StandardAmigaFileHandles
  141.  *    zurück.
  142.  */
  143. static    BPTR    std_input,std_output;
  144.  
  145. /*
  146.  *    Command List ist ein Zeiger auf Feld von RexxCommandStrukturen.
  147.  *    In dieser Struktur steht der FunktionsName und ein Zeiger auf die
  148.  *    Funktion. Kommt einen Message zum internen RexxMessageHandler,
  149.  *    so wird die Liste nach einer Funktion des gegebenen Namens und
  150.  *    springt die Funktion an.
  151.  *    Der letzte Eintrag der Tabelle muß als Namen einen NullZeiger
  152.  *    beinhalten.
  153.  *    Die Funktion wird mit folgenden Parametern auf gerufen:
  154.  *    ret=func(arg0,rexx_mess);
  155.  *    arg0 ist ein Zeiger auf den StringRest der nach dem Kommando folgt.
  156.  *    rexx_mess ist ein Zeiger auf die RexxStruktur.
  157.  *    Gibt die Funktion TRUE als RET zurück, so übernimmt der Handler
  158.  *    das beantworten der Message.
  159.  */
  160. static    struct RexxCommand    *command_table;
  161.  
  162.  
  163.  
  164.  
  165. /*********************************************************************/
  166. /*    Die Funktion OpenRexx öffnet, wenn möglich einen RexxPort.   */
  167. /*********************************************************************/
  168.  
  169. ULONG OpenRexx(char * name,const char *ext, __stkargs void (*do_res)(struct RexxMsg *rmsg),BPTR in, BPTR out)
  170. /*
  171.  * OpenRexx    initialisiert die ARexxumgebung. Dafür wird, wenn benötigt
  172.  *    Arexxlibrary geöffnet, ein Port initialisiert, die Defaultextension
  173.  *    festgelegt und die std Ein- und Ausgabekanäle bestimmt.
  174.  *
  175.  * --> name    Name des ARexxPorts den unser Programm bekommt.
  176.  *        Existiert ein solcher Port bereits wird der FehlerCode
  177.  *        ERROR_PORT_ALLREADY_EXISTS zurückgegeben
  178.  * --> ext    Zeiger auf die extension, wenn NULL dan .REXX
  179.  * --> do_res    Zeiger auf die Funktion zum Message handling.
  180.  *        Wird aufgerufen wenn während der Arbeit ein RexxMsg anfällt
  181.  * --> in,out    std input/output handle
  182.  * <-- RESLUT    SigBit     Success FALSE wenn nicht geöffnet
  183.  */
  184. {
  185.    /*    Portname vorhanden ?    */
  186.    if (name==0 || strlen(name)==0)
  187.    {
  188.       error=RERROR_INVALID_PORT_NAME;
  189.       return(0);
  190.    }
  191.  
  192.    /*    Prüfen ob ARexx schon geöffnet ist, wenn ja, */
  193.    /*    dann keinen Port öffnen */
  194.    if (RexxSysBase)
  195.    {
  196.       error=RERROR_AREXX_ALLREADY_OPEN;
  197.       return(0);
  198.    }
  199.  
  200.    /*    ARexxLib öffnen */
  201.    if ((RexxSysBase=(struct RxsLib *)OpenLibrary("rexxsyslib.library",0))==0)
  202.    {
  203.       error=RERROR_NO_AREXX;
  204.       return(0);
  205.    }
  206.  
  207.    /*    Prüft ob ein Port mit dem selben Namen existiert,  */
  208.    /*    wenn ja bricht das Programm mit einem Fehler ab.   */
  209.    Forbid();
  210.    if (FindPort(name))
  211.    {
  212.       Permit();
  213.       CloseLibrary((struct Library *)RexxSysBase);
  214.       RexxSysBase=0;
  215.       error=RERROR_PORT_ALLREADY_EXISTS;
  216.       return(0);
  217.    }
  218.  
  219.    /*  Port kreieren, wenn möglich  */
  220.    if ((rexx_port=CreatePort(name,0))==0)
  221.    {
  222.       /* konnte keinen Port aufmachen */
  223.       Permit();
  224.       error=RERROR_NO_PORT;
  225.       CloseLibrary((struct Library *)RexxSysBase);
  226.       RexxSysBase=0;
  227.       return(0);
  228.    }
  229.    Permit();
  230.  
  231.    /*    E/A-Kanäle festlegen    */
  232.    if (in<0)    std_input=Input();
  233.    else     std_input=in;
  234.    if (out<0)   std_output=Output();
  235.    else     std_output=out;
  236.  
  237.    /*    extension zuweisen    */
  238.    default_extension=ext;
  239.  
  240.    /*    ResultFunktions Pointer setzen    */
  241.    process_message=do_res;
  242.  
  243.    /*    keine Messages */
  244.    outstanding_replies=0;
  245.  
  246.    /*    FunktionTable löschen */
  247.    command_table=0;
  248.  
  249.    /* Zeiger auf den MessagePort zurückgeben   */
  250.    return ((ULONG)1L<<rexx_port->mp_SigBit);
  251. }
  252.  
  253. BOOL AttempCloseRexx(void)
  254. /*
  255.  AttempCloseRexx
  256.     probiert den ARexxPort zu schliessen (funktioniert nur, wenn
  257.     OutstandingReplies==0 ist), kann das RexxSystem geschlossen
  258.     werden kommt TRUE zurück, sonst False
  259. */
  260. {
  261.    if (outstanding_replies>0)
  262.       return(FALSE);
  263.    return(CloseRexx());
  264. }
  265.  
  266. /******************************************************************/
  267. /*    beantwortet alle anstehenden Messages, mit RXRERRORIMGONE  */
  268. /*    wartet auf alle noch zu beantwortenden Messages       */
  269. /*    schließt den Port                      */
  270. /*    schließt die ArexxSysBase                  */
  271. /******************************************************************/
  272.  
  273. BOOL CloseRexx(void)
  274. {
  275.    struct    RexxMsg *rmsg;
  276.  
  277.    /*    prüft ob es übehaupt etwas zu schließen gibt    */
  278.    if (RexxSysBase==0)
  279.    {
  280.       error=RERROR_AREXX_NOT_OPEN;
  281.       return(FALSE);
  282.    }
  283.  
  284.    /*
  285.     *    Achtung diese Funktion prüft nur, ob alle abgeschickten
  286.     *    Messages eine Antwort bekommen haben. Nicht aber ob alle
  287.     *    angekommenen Messages beantwortet wurden.
  288.     *    Antworten wandern ins NIL
  289.     */
  290.    while (outstanding_replies)
  291.    {
  292.       /* Message vom Port holen */
  293.       while ((rmsg = (struct RexxMsg *)GetMsg (rexx_port)) == 0)
  294.      WaitPort ((struct MsgPort *)rexx_port);
  295.  
  296.       /* gesuchte antwort ? */
  297.       if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
  298.       {
  299.      /* erwartete antwort, message freigeben */
  300.      RemoveRexxMsg (rmsg);
  301.  
  302.      outstanding_replies --;
  303.       } else
  304.       {
  305.      /* alle jetzt ankommenden Kommandos dankent ablehnen
  306.       * sollte es eine no-return message sein, den Speicher
  307.       * freigeben und weitermachen, sonst mit RXRERRORIMGONE
  308.       * beantworten
  309.       */
  310.      if (rmsg->rm_Action & RXFF_NONRET)
  311.      {
  312.         RemoveRexxMsg (rmsg);
  313.      } else
  314.      {
  315.         rmsg->rm_Result2 = 0;
  316.         rmsg->rm_Result1 = RERROR_IMGONE;
  317.  
  318.         ReplyMsg((struct Message *) rmsg);
  319.      }
  320.       }
  321.    } /* while outstanding_replies */
  322.  
  323.    /* Port vom System löschen    */
  324.    DeletePort (rexx_port);
  325.  
  326.    /* ArexxLib schließen    */
  327.    CloseLibrary ((struct Library *)RexxSysBase);
  328.    RexxSysBase = 0;
  329.  
  330.    return (TRUE);
  331. }
  332.  
  333.  
  334. /********************************************************************/
  335. /*    Mit dieser Funktion kann man den letzten aufegetreten        */
  336. /*    FehlerCode festellen                        */
  337. /********************************************************************/
  338. long LastRexxError(void)
  339. {
  340.    return(error);
  341. }
  342.  
  343.  
  344. /****************************************************************/
  345. /*    BuildRexxMsg erstellt eine ARexx Message und füllt    */
  346. /*    die Argument slots mit den Parametern            */
  347. /****************************************************************/
  348. /*
  349.  *    Aufruf erfolgt: BuildRexxMsg(com,flags,arg0,arg1,arg2,...,argn)
  350.  *    Es dürfen maximal 15 Argumente übergeben werden. Weitere Argumente
  351.  *    werden ignoriert. Will man nur 3 Argumente übergeben (arg1-arg3)
  352.  *    übergibt man als letztes Argument (arg4) NULL
  353.  *    Die Funktion gibt einen Zeiger auf die erstellte Message zurück,
  354.  *    im Fehlerfalle NULL.
  355.  */
  356. struct RexxMsg *BuildRexxMsg
  357. (
  358.    /*
  359.     *       com ist der Name des aufzurufenden Kommandos.
  360.     *       Alles Strings (com & args) sind normale mit NULL abgeschloßene
  361.     *       C-Strings.
  362.     */
  363.    const char     *com,
  364.    /*
  365.     *       action dieses Flag wir direkt im Command (action) Field
  366.     *       der RexxMessage struktur eingefügt
  367.     */
  368.    const long     action,
  369.    /*
  370.     *       first_arg is ein Zeiger auf das erste Argument (aufruf der
  371.     *       Funktion s.o.
  372.     *       Aufgrund der internen Handhabung wird nur der erste Parameter im
  373.     *       Funktionskopf angenommen.
  374.     *       Die Argumente sind normale 0-terminierte C-Strings
  375.     */
  376.    char    *first_arg,
  377.    /*
  378.     *       Weitere Argumente:
  379.     */
  380.    ...
  381. )
  382. {
  383.    struct    RexxMsg *rmsg;
  384.    register    i;
  385.    char     **args;
  386.  
  387.    /*    Rexx geöffnet ? */
  388.    if    (RexxSysBase==0)
  389.    {
  390.       error=RERROR_AREXX_NOT_OPEN;
  391.       return(0);
  392.    }
  393.  
  394.    /*    gültiges Kommando ? */
  395.    if    (com==0 || *com==0)
  396.    {
  397.       error=RERROR_INVALID_COMMAND_NAME;
  398.       return(0);
  399.    }
  400.  
  401.    /* RexxMessage-Body erstellen */
  402.    if ((rmsg=CreateRexxMsg(rexx_port,default_extension, rexx_port->mp_Node.ln_Name))==0)
  403.    /*    konnte keine RexxMessage erstellen */
  404.    {
  405.       error=RERROR_OUT_OF_MEMORY;
  406.       return(0);
  407.    }
  408.  
  409.  
  410.    /* Die Kommandos und Argumente einfügen */
  411.    /* erst das Kommando */
  412.    rmsg->rm_Args[0]=(STRPTR) com;
  413.  
  414.    /*
  415.     * Die Argumente einlesen. Zur einfacheren Verarbeitung generieren
  416.     * wir ein Feld in dem die Argumente stehen, und das man mit einer
  417.     * Schleife abarbeiten kann
  418.     */
  419.    args=&first_arg;
  420.  
  421.    /* Jetzt alle Argumente bis zum ersten NULL argument in die
  422.       Message eintragen.*/
  423.    for (i=1;i<15 && args[i-1];i++)
  424.       rmsg->rm_Args[0]=(STRPTR) args[i-1];
  425.  
  426.    /*
  427.     * Mit der Funktion FillRexxMsg kann man nun die Strings in der
  428.     * Message durch Rexx Argsstrings ersetzen lassen.
  429.     */
  430.    if (!FillRexxMsg(rmsg,i,0))
  431.    {
  432.       /*
  433.        * wahrscheinlich zuwenig mem für die Umwandlung, also
  434.        * ErrorCode setzen, die nicht gebrauchte Message zurückgeben
  435.        * und Abgang
  436.        */
  437.       error=RERROR_OUT_OF_MEMORY;
  438.       DeleteRexxMsg(rmsg);
  439.       return(0);
  440.    }
  441.  
  442.    /* Command feld initialisieren */
  443.    rmsg->rm_Action=action;
  444.  
  445.    return(rmsg);
  446. }
  447.  
  448.  
  449. /*****************************************************************/
  450. /*    Dies Funktion gibt den Speicher einer RexxMessage frei.  */
  451. /*    Also die Argumente, einen ggf vorhandenen ReturnWert     */
  452. /*    und die Message selbst. Aus diesem Grund müßen Felder     */
  453. /*    (Argumente und Return Code, wenn sie außerhalb der       */
  454. /*    Funktion freigegeben worden sind auf NULL gesetzt werden */
  455. /*****************************************************************/
  456. BOOL RemoveRexxMsg
  457. (
  458.    /* Zeiger auf die zu löschende RexxMessage */
  459.    /*
  460.     *       gibt TRUE für Erfolg zurück
  461.     */
  462.    struct    RexxMsg *rmsg
  463. )
  464. {
  465.    /* Rexx geöffnet ? */
  466.    if (RexxSysBase==0)
  467.    {
  468.       error=RERROR_AREXX_NOT_OPEN;
  469.       return(FALSE);
  470.    }
  471.  
  472.    /*
  473.     * Als erstes prüfen, ob ein Return String vorhanden ist,
  474.     * wenn ja, dann löschen. Diese Funktion löscht den ReturnString
  475.     * nur dann, wenn in Action ein Result gefordert ist. Und kein
  476.     * Error im Result1 Feld eigetragen ist.
  477.     */
  478.    if ((rmsg->rm_Action&RXFF_RESULT) && rmsg->rm_Result1==0 && rmsg->rm_Result2!=0)
  479.    {
  480.       DeleteArgstring((char *)rmsg->rm_Result2);
  481.       rmsg->rm_Result2=0;
  482.    }
  483.  
  484.    /*
  485.     * Alle übergebenen Argumente mit ClearRexxMsg löschen.
  486.     * Bei dieser Funktion werden alle Argumente die nicht NULL sind
  487.     * als RexxStringPointer interpretiert und diese Strings freigegeben
  488.     */
  489.    ClearRexxMsg(rmsg,16);
  490.  
  491.    /* zum Abschluß noch die eigentliche Message freigeben */
  492.    DeleteRexxMsg(rmsg);
  493.    return(TRUE);
  494. }
  495.  
  496.  
  497. /****************************************************************/
  498. /*    PutRexxMsg schickt eine Message an den genannten Port    */
  499. /*    un übernimmt die Buchführung über fehlende Antworten    */
  500. /****************************************************************/
  501. BOOL PutRexxMsg
  502. (
  503.    /*
  504.     *       Port ist der Name des Ziel Ports. Der Name ist NULL beendeter
  505.     *       String. Achtung !! kein PortPointer.
  506.     *       Ist port NULL so wird die Message an den RexxHostPort geschickt.
  507.     *       Da man einen eigenen Namen angeben kann, ist möglich, Messages
  508.     *       direkt an andere Rexxfähige Programme zu senden.
  509.     */
  510.    char    *port,
  511.    /*
  512.     *       rmsg    ist ein Zeiger auf gültige, vollstänig initialisierte
  513.     *       RexxMessage-Struktur.
  514.     */
  515.    struct    RexxMsg *rmsg
  516. )
  517. {
  518.    struct    MsgPort     *msg_port;
  519.  
  520.    /*    Rexx opened ? */
  521.    if (RexxSysBase==0)
  522.    {
  523.       error=RERROR_AREXX_NOT_OPEN;
  524.       return(FALSE);
  525.    }
  526.  
  527.    /*    Prüfen ob der standard RexxPort gefragt ist, wenn ja */
  528.    /*    dann RXSDIR ("REXX") einsetzen                       */
  529.    if (port==0)
  530.       port=RXSDIR;
  531.  
  532.    /*    Prüfen ob es überhaupt einen PortNamen gibt, wenn nicht
  533.     *    Fehler */
  534.    if (*port==0)
  535.    {
  536.       error=RERROR_NO_PORT;
  537.       return(FALSE);
  538.    }
  539.  
  540.    /*    Message Port suchen */
  541.    Forbid();
  542.    if ((msg_port=FindPort(port))==0)
  543.    {
  544.       /* gewünschter Port existiert nicht    */
  545.       Permit();
  546.       error=RERROR_UNKNOWN_DESTINATION_PORT;
  547.       return(FALSE);
  548.    }
  549.    PutMsg((struct MsgPort *)msg_port,(struct Message *) rmsg);
  550.    Permit();
  551.  
  552.    /* abgeschickte Message merken */
  553.    if ((rmsg->rm_Action & RXFF_NONRET) == 0)
  554.    {
  555.       outstanding_replies ++;
  556.    }
  557.  
  558.    return (TRUE);
  559. }
  560.  
  561.  
  562. /****************************************************************/
  563. /*    GetRexxMsg funktioniert GetMsg des Betriebsystems,    */
  564. /*    nur das Über die Messages Buchgeführt wird        */
  565. /****************************************************************/
  566. struct RexxMsg *GetRexxMsg(void)
  567. /*
  568.  *    Die Funktion gibt einen Zeiger auf die Message oder NULL
  569.  *    zurück.
  570.  *    Ist NULL ein Fehler, so kann das mit LastRexxError festgestellt
  571.  *    werden. Sonst bedeutet es einfach, das keine Msg am Port
  572.  *    wartet.
  573.  */
  574. {
  575.    struct    RexxMsg *rmsg;
  576.  
  577.    /* Rexx geöffnet ? */
  578.    if (RexxSysBase==0)
  579.    {
  580.       error=RERROR_AREXX_NOT_OPEN;
  581.       return(0);
  582.    }
  583.    error=0;
  584.  
  585.    /* Message holen */
  586.    if ((rmsg=(struct RexxMsg *)GetMsg(rexx_port))==0)
  587.       /* keine Message am Port also return(0) */
  588.       return(0);
  589.  
  590.    /* Überprüfen ob es eine Antwort auf eine von uns abgeschickte
  591.     * Message ist. Wenn ja die Antwort veruchen.
  592.     * Achtung !! Auch die Rückantwort wird nicht freigegeben
  593.     */
  594.    if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
  595.       outstanding_replies--;
  596.  
  597.    return(rmsg);
  598. }
  599.  
  600.  
  601. /****************************************************************/
  602. /*    FetchRexxMsg wartet bis eine Message an unserm        */
  603. /*    Port ankommt und gibt diese zurück.            */
  604. /****************************************************************/
  605. struct RexxMsg *FetchRexxMsg(void)
  606. /*
  607.  *    Die Funktion kehrt mit einem Zeiger auf die vom
  608.  *    Port geholte Message zurück.
  609.  */
  610. {
  611.    struct    RexxMsg *rmsg;
  612.  
  613.    /* Rexx geöffnet ? */
  614.    if (RexxSysBase==0)
  615.    {
  616.       error=RERROR_AREXX_NOT_OPEN;
  617.       return(0);
  618.    }
  619.  
  620.    while ((rmsg=GetRexxMsg())==0)
  621.       WaitPort(rexx_port);
  622.  
  623.    return(rmsg);
  624. }
  625.  
  626.  
  627. /****************************************************************/
  628. /*    ReplyRexxMsg    setzt den ArexxErrorCode, füllt den    */
  629. /*    Returnwert_slot und beantwortet die Message.        */
  630. /*    sollte es eine NonReply Message sein, so wird sie    */
  631. /*    einfach gelöscht                    */
  632. /****************************************************************/
  633. BOOL ReplyRexxMsg
  634. /*
  635.  *    Im falle eines Fehlers kehrt die Funktion mit FALSE zurück.
  636.  *    Nähere Information kann man LastRexxError holen
  637.  */
  638. (
  639.    /*
  640.     *       rmsg    ist ein Zeiger auf die zu beantwortende Message
  641.     */
  642.    struct  RexxMsg *rmsg,
  643.    /*
  644.     *       rexx_error ist ein Langwort, das den ArexxErrorCode enthält.
  645.     *       Der Code wird in das Result1 Feld der Message eingetragen.
  646.     */
  647.    long    rexx_error,
  648.    /*
  649.     *       return_string ist ein String, der als Return wert and den
  650.     *       Caller zurückgegeben wird. ReplyRexxMsg generiert aus diesem
  651.     *       C-String ein ArexxArgument und füllt dieses in das Result2
  652.     *       Feld ein.
  653.     *       Ist rexx_error != 0, also ein Fehler aufgetreten, so wird der
  654.     *       String ignoriert und das Feld auf NULL gesetz. Soll kein
  655.     *       Returnwert zurückgegeben werden ist ein NULL-Pointer zu übergeben.
  656.     */
  657.    char    *return_string
  658. )
  659. {
  660.    STRPTR      rx_string;
  661.  
  662.    /*    Rexx geöffnet ? */
  663.    if (RexxSysBase==0)
  664.    {
  665.       error=RERROR_AREXX_NOT_OPEN;
  666.       return(FALSE);
  667.    }
  668.  
  669.    /*    Message übergeben worden ? */
  670.    if (rmsg==0)
  671.    {
  672.       error=RERROR_NO_MSG;
  673.       return(FALSE);
  674.    }
  675.  
  676.    /* Ist es eine NonRet, wenn ja, so wird die Message
  677.     * nicht beantwortet, sondern gelöscht.
  678.     */
  679.    if (rmsg->rm_Action & RXFF_NONRET)
  680.    {
  681.       RemoveRexxMsg(rmsg);
  682.       return(TRUE);
  683.    }
  684.  
  685.    /*    ErrorCode eintragen    */
  686.    rmsg->rm_Result1=rexx_error;
  687.  
  688.    /*
  689.     *    im FehlerFalle Result2 auf NULL setzen, das ist zwar nach
  690.     *    der ARexx Dokumentation nicht nötig, aber man weis ja
  691.     *    nie mit wem es HRexx zu tun hat.
  692.     */
  693.    if (rexx_error)
  694.       rmsg->rm_Result2=NULL;
  695.    else
  696.       /*
  697.        * Wenn kein Fehler aufgetreten ist und eine ReturnString übergeben
  698.        * wurde und die Message eine Antowrt erwartet, so wird aus dem
  699.        * return_string ein Argument String erstellt und an den Caller
  700.        * zurückgegeben
  701.        */
  702.       if (return_string && (rmsg->rm_Action & RXFF_RESULT))
  703.       {
  704.      rx_string=(STRPTR) CreateArgstring(return_string,strlen(return_string));
  705.      if (rx_string==0)
  706.      {
  707.         /*
  708.          * Falls kein String erstellt werden kann, wird die
  709.          * Funktion mit eine Fehler abgebrochen. In diesem Fall
  710.          * kann man es z.B. damit versuchen, das man keinen
  711.          * return_string übergibt
  712.          */
  713.         error=RERROR_OUT_OF_MEMORY;
  714.         return(FALSE);
  715.      }
  716.      rmsg->rm_Result2=(LONG)rx_string;
  717.       }
  718.  
  719.    /* unsere hübsche Message zurück an den Chef */
  720.    ReplyMsg((struct Message *) rmsg);
  721.    return(TRUE);
  722. }
  723.  
  724.  
  725. /**********************************************************************/
  726. /*    SyncRexxCommand sendet ein Kommando, und wartet bis das       */
  727. /*    Kommando abgearbeitet ist. Sollten in der Zwischenzeit          */
  728. /*    Kommandos an unser Port gehen, wird die Funktion          */
  729. /*    process_message mit dem Zeiger auf die Message aufgerufen.    */
  730. /*    So ist es möglich, währen eines SyncAufrufes Kommandos zu     */
  731. /*    Empfangen. SyncRexxCommand unterstützt einen returncode.      */
  732. /*    Dazu muß eine StringBuffer und die Größe des Buffer über-     */
  733. /*    geben werden .                              */
  734. /*    Der aufruf erfolgt:                          */
  735. /*    SyncRexxCommand(port,com,result,result_len,arg1,arg2,...,argn)*/
  736. /*    Werden nicht alle Argumente genutzt, muß das letzte Argument  */
  737. /*    NULL sein. Mehr als 15 Argumente werden ignoriert.          */
  738. /**********************************************************************/
  739. long SyncRexxCommand
  740. /*
  741.  *    Die Funktion kehrt mit dem ArexxErrorCode oder dem Internen
  742.  *    errorcode zurück.
  743.  *    0 für eine erfolgreiche aktion.
  744.  *    Kommt es zu einem RexxFehler, so wird der ResultString gelöscht.
  745.  */
  746. (
  747.    /*
  748.     *       port ist der Name des Ports an den das Kommando gesendet werden soll.
  749.     *       wird als PortName 0 angegeben, so wird das Kommando an den Rexx-
  750.     *       Host geschickt.
  751.     */
  752.    const char     *port,
  753.    /*
  754.     *       Com ist der String der den KommandoNamen enthält
  755.     */
  756.    const char     *com,
  757.    /*
  758.     *       result ist ein Pointer auf den StringBuffer in den der
  759.     *       ResultString des Kommandos kopiert werden soll. Ist result == NULL
  760.     *       oder result_len == NULL so wird die Fukntion als Kommando
  761.     *       ohne ReturnWert betrachtet, und die Flags in der RexxMsg
  762.     *       entsprechend gesetzt.
  763.     */
  764.    char    *result,
  765.    long    result_len,
  766.    /*
  767.     *       first_arg Zeiger auf den ersten Argument String. Der aufruf Syntax
  768.     *       ist oben beschrieben, und Funktioniert wie bei BuildRexxMessage.
  769.     */
  770.    char    *first_arg,
  771.    /*
  772.     *    weitere args
  773.     */
  774.     ...
  775. )
  776. {
  777.    char **args;
  778.    struct    RexxMsg *rmsg;
  779.    struct    RexxMsg *our_msg;
  780.    long     flag;
  781.    register    i;
  782.    register    char    *s;
  783.  
  784.    /*    Rexx geöffnet ? */
  785.    if (RexxSysBase==0)
  786.    {
  787.       error=RERROR_AREXX_NOT_OPEN;
  788.       return(-1);
  789.    }
  790.  
  791.    /* wurde ein Kommando übergeben ? */
  792.    if (com==0 || *com==0)
  793.    {
  794.       error=RERROR_INVALID_COMMAND_NAME;
  795.       return(-1);
  796.    }
  797.  
  798.    /* prüfen ob ein Result erwartet wird und die Flags für die
  799.     * Message entprechend vorbereiten
  800.     */
  801.    flag=RXCOMM;
  802.    if (result && result_len) flag|=RXFF_RESULT;
  803.  
  804.    /* Argumente Feld übernehmen */
  805.    args=&first_arg;
  806.    /* Die Message erstellen */
  807.    our_msg=BuildRexxMsg(com,flag,args[0],args[1],args[2],args[3],
  808.     args[4],args[5], args[6],args[7],args[8],args[9],args[10],
  809.     args[10],args[11], args[12],args[13],args[14]);
  810.    /* geklappt ?*/
  811.    if (our_msg==0) return(-1);
  812.  
  813.    /* let's fets und schon schicken wir die Msg ab */
  814.    if (!PutRexxMsg(port,our_msg))
  815.    {
  816.       /* speicher der Message freigeben */
  817.       RemoveRexxMsg(our_msg);
  818.       return(-1);
  819.    }
  820.  
  821.    /* jetzt warten wir bis unsere Message beantwortet zurück kommt */
  822.    do
  823.    {
  824.       rmsg=FetchRexxMsg();
  825.  
  826.       /* unsere Message ? */
  827.       if (rmsg==our_msg) break;
  828.  
  829.       /* eine Antwort auf eine alte Message ? */
  830.       if (rmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
  831.      RemoveRexxMsg(rmsg);
  832.       else
  833.      /*
  834.       * haben wir eine Funktion die für die Bearbeitung
  835.       * ankommender Messages zuständig ist ?
  836.       * wenn ja, dann Funktion anspringen, sonst Message mit
  837.       * Unknown Command zurückgeben
  838.       */
  839.      if (process_message!=0)
  840.      {
  841.         (*process_message)(rmsg);
  842.      }
  843.      else
  844.         ReplyRexxMsg(rmsg,ERR10_030,0);
  845.    } /* auf Antwort warten */
  846.    while (TRUE);
  847.  
  848.    /* error code retten */
  849.    flag=our_msg->rm_Result1;
  850.  
  851.    /* wenn kein error aufgetreten ist und ein Result erwartet wird
  852.     * wird der Result String in den Buffer kopiert
  853.     */
  854.    if (flag==0 && result && result_len)
  855.    {
  856.       /* Zeiger Resultstring holen    */
  857.       if (s=(char *)rmsg->rm_Result2)
  858.       {
  859.      for (i=0;i<(result_len-1) && s[i];i++)
  860.         result[i]=s[i];
  861.      result[i]=0;
  862.      if (s[i]!=0)
  863.      {
  864.         /* wenn der Ergebniss string zu lang ist error code setzen
  865.          * zurückgeben und den string mittendrin abbrechen.
  866.          */
  867.         flag=RERROR_STRING_TOO_LONG;
  868.      }
  869.       } else
  870.      *result = 0;
  871.    }
  872.    RemoveRexxMsg(our_msg);
  873.    return(flag);
  874. }
  875.  
  876. /****************************************************************/
  877. /*    RexxMessageHandler sucht die FunktionsListe durch, und    */
  878. /*    ruft, falls es das Kommando gibt, die dazugehörige    */
  879. /*    Funktion auf. Sollte das Kommando nicht existieren    */
  880. /*    wird der ARexxFehlerCode Label NotFound zurückgegeben.    */
  881. /****************************************************************/
  882. __stkargs void RexxMessageHandler (struct RexxMsg *rmsg)
  883. /*
  884.  * RexxMessageHandler ruft bei ankommenden Messages die in der
  885.  * Funktionliste übergebenen Kommandos auf.
  886.  *
  887.  * --> rmsg    Zeiger auf die RexxMessage, die bearbeitet werden soll
  888.  */
  889. {
  890.    register    i;
  891.    register    act_com;
  892.    char     *s;
  893.  
  894.    /*    existier ein CommandTable ? */
  895.    if (command_table==0)
  896.    {
  897.       /* Message mit Unknown Label beantworten */
  898.       ReplyRexxMsg(rmsg,ERR10_030,0);
  899.       return ;
  900.    }
  901.  
  902.  
  903.    /*    Zeiger auf den Commando String holen */
  904.    s=(char *)rmsg->rm_Args[0];
  905.  
  906.    /*
  907.     * Kommando liste nach dem Kommando druchsuchen, wenn die Funktion
  908.     * gefunden wird, aufrufen sonst mit UNKNOWN_LABEL beantworten.
  909.     * Aufgrund der Vergleichs Funktion müßen Kommandos, die als Anfang
  910.     * in einem anderen Kommando der Tabelle enthalten sind hinter
  911.     * diesen stehen, das sonst die längeren Kommandos nicht gefunden
  912.     * würden.
  913.     * So  muß  die Funktion "test" nach der Funktion "testme" stehen.
  914.     * Beim vergleich wird die groß klein Schreibung ignoriert.
  915.     * Strings mit der Länge 0 verwirren die Funktion ebenfalls.
  916.     */
  917.    for (act_com=0;command_table[act_com].Name;act_com++)
  918.    {
  919.       /* String vergleichen */
  920.       for (i=0;(toupper(command_table[act_com].Name[i])==toupper(s[i])) && (s[i]!=0);i++);
  921.       if (command_table[act_com].Name[i]==0)
  922.       {
  923.      /* Skip Spaces in Kommando bis zu argumenten */
  924.      while (s[i]==32) i++;
  925.      /* Funktion aufrufen */
  926.      if (command_table[act_com].Function(s+i,rmsg))
  927.         /* Message beantworten */
  928.         ReplyRexxMsg(rmsg,0,0);
  929.      goto done;
  930.       }
  931.    }
  932.  
  933.    /* Kommando unbekannt */
  934.    ReplyRexxMsg(rmsg,ERR10_030,0);
  935.  
  936.    done:;
  937. }
  938.  
  939.  
  940. /****************************************************************/
  941. /*    ChangeProcessMessage    ändert den Zeiger der process_    */
  942. /*    message funktion.                    */
  943. /****************************************************************/
  944. void * ChangeProcessMessage(__stkargs void (*new_function)(struct RexxMsg * rmsg))
  945. /*
  946.  * ChangeProcessMessage ändert die Funktion für das InterneMessagehandling
  947.  *
  948.  * --> new_function    Zeiger auf die neue Funktion, bei -1 wird
  949.  *        der HRexx interne Handler verwendet
  950.  * <-- RESULT    Pointer auf alten hndler
  951.  */
  952. {
  953.    void   (*old_function)(struct RexxMsg * rmsg);
  954.  
  955.    /* alte Funktion zurückgeben */
  956.    old_function=process_message;
  957.  
  958.    /*    Internen handler ? */
  959.    if ((long)new_function==-1)
  960.       process_message = RexxMessageHandler;
  961.    else
  962.       process_message = new_function;
  963.  
  964.    if ((long)old_function==(long)RexxMessageHandler)
  965.       old_function=(void (*)(struct RexxMsg *))-1;
  966.  
  967.    return (old_function);
  968. }
  969.  
  970. /****************************************************************/
  971. /*    SetRexxCommandTable  ändert die interne Kommandotabelle */
  972. /****************************************************************/
  973. struct RexxCommand * SetRexxCommandTable
  974. (
  975.    /*
  976.     *       Zeiger auf eine vom Benutzer definierte Kommando Tabelle
  977.     */
  978.    struct  RexxCommand       *new_com_tab
  979.    /*
  980.     *       gibt den Zeiger auf die alte Funktiontabelle zurück.
  981.     */
  982. )
  983. {
  984.    struct RexxCommand       *old_com_tab;
  985.  
  986.    old_com_tab=command_table;
  987.    command_table=new_com_tab;
  988.  
  989.    /* Ist der FunktionTable != NULL so wird die Handler Funktion
  990.     * auf den internen MessageHandler umgelenkt. Sonst wird der Message
  991.     * Handler Pointer auf NULL gesetzt, wenn er vorher auf den
  992.     * RexxMessageHandler gezeigt hat
  993.     */
  994.    if (command_table!=0)
  995.    {
  996.       ChangeProcessMessage((void *)-1);
  997.    }
  998.    else
  999.       if ((long)process_message==(long)RexxMessageHandler)
  1000.      process_message=0;
  1001.  
  1002.    return(old_com_tab);
  1003. }
  1004.  
  1005. /*************************************************************/
  1006. /*  ModifyRepCount  ändert Anzahl fehlender Messages         */
  1007. /*************************************************************/
  1008. long ModifyRepCount(long delta)
  1009. /*
  1010.  ModifyRepCount
  1011.     ändert den Counter mit den fehlenden Messages um den in
  1012.     delta angegebenen Betrag.
  1013.     Der alte wert von RepCount wird zurückgegeben
  1014. */
  1015. {
  1016.    long old;            /* alter wert von outstandig_replies */
  1017.  
  1018.    old=outstanding_replies;    /* alten wert merken */
  1019.    outstanding_replies+=delta;    /* ändern */
  1020.    return(old);
  1021. }
  1022.  
  1023.  
  1024. #ifdef DEBUG
  1025. /* testing enviroment */
  1026.  
  1027. #include <stdio.h>
  1028. hallo(arg)
  1029. char    *arg;
  1030. {
  1031.    printf("Rexx called hallo with:\"%s\"\n",arg);
  1032.    return (TRUE);
  1033. }
  1034.  
  1035. struct    RexxCommand    rcs[]=
  1036. {
  1037.    "hallo",(void *)hallo,
  1038.    0,0
  1039. };
  1040.  
  1041.  
  1042. main(argc,argv)
  1043. long   argc;
  1044. char **argv;
  1045. {
  1046.    struct    RexxMsg *rmsg;
  1047.    char     result[100];
  1048.    long error;
  1049.  
  1050.    if (OpenRexx("RexxTest","test",0,-1,-1)==0)
  1051.    {
  1052.       printf("OpenError %ld\n",LastRexxError());
  1053.       goto err;
  1054.    }
  1055.  
  1056.    SetRexxCommandTable(rcs);
  1057.  
  1058.    result[0]=0;
  1059.  
  1060.    error=SyncRexxCommand(0,"ootest tatara",result,100,0);
  1061.    printf("%ld %s\n",error,result);
  1062.  
  1063.    err:;
  1064.    CloseRexx();
  1065. } /* main */
  1066. #endif
  1067.