home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / wp_dtp / xdme1820.lha / XDME / hrexx.c < prev    next >
C/C++ Source or Header  |  1993-02-27  |  30KB  |  1,058 lines

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