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