home *** CD-ROM | disk | FTP | other *** search
/ MACD 4 / MACD4.iso / Emulatory / AROS / alib / boopsi.c next >
Encoding:
C/C++ Source or Header  |  1978-03-06  |  12.8 KB  |  497 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: boopsi.c,v 1.2 1996/10/25 14:35:09 aros Exp $
  4.  
  5.     Desc:
  6.     Lang: english
  7. */
  8.  
  9. /*******************************************************************************
  10.  
  11.     MODUL
  12.     boopsi.c
  13.  
  14.     DESCRIPTION
  15.     Implementiert BOOPSI - Basic Object Oriented Programming System
  16.     for Intuition. BOOPSI gestattet C++-Methoden in Standard ANSI
  17.     bzw K&R-C zu verwenden. Die Vorgehensweise ist wie folgt:
  18.  
  19.         BOOPSI arbeitet mit sog. Message-Dispatchern. Ein Message
  20.     Dispatcher ist im Prinzip nichts anderes als eine Routine, die
  21.     Nachrichten an ein Object auswertet. Diese Nachricht ist nichts
  22.     anderes als eine Structur mit ID. Die ID bestimmt den Typ der
  23.     Nachricht (z.B. Setzte Attribute des Objects).
  24.  
  25.         Der Vorteil von BOOPSI liegt darin, dass die Zugriffsfunktionen
  26.     alle extern zum Object und standardisiert sind. Der Benutzer eines
  27.     Object muss sich nicht mehr viele verschiedene Funktionsnamen merken
  28.     sondern kann mit fuenf Funktionen alle Operationen auf Objecte
  29.     durchfuehren. Diese Operationen sind:
  30.  
  31.         - Erzeuge ein neues Object (eine neue Instanz des Objects)
  32.         - Loese ein Object auf
  33.         - Setze Attribute des Objects
  34.         - Frage Attribute des Objects ab
  35.         - Wende eine Methode auf das Object an.
  36.  
  37.     NOTES
  38.  
  39.     BUGS
  40.  
  41.     TODO
  42.  
  43.     EXAMPLES
  44.     // Beispiel eines kompletten Line-Objects
  45.  
  46.     // Hier wird die Instance-Data definiert. Der Speicher fuer diese
  47.     // Struktur wird vom Betriebssystem angelegt und verwaltet.
  48.     struct LineData
  49.     {
  50.         FLOAT coords[4];
  51.         ULONG width;
  52.         ULONG style;
  53.     };
  54.  
  55.     // In einem Include-File sind folgende Tags definiert:
  56.     //
  57.     //    LINE_StartX, (FLOAT, CSG)
  58.     //    LINE_StartY, (FLOAT, CSG)
  59.     //    LINE_EndX, (FLOAT, CSG)
  60.     //    LINE_EndY, (FLOAT, CSG)
  61.     //    LINE_Width, (INT, CSG)
  62.     //    LINE_Style, (INT, CSG)
  63.     //
  64.     // und folgende Methoden
  65.     //
  66.     //    LINEM_Display, (GC)
  67.     //
  68.     // Mit diesen lassen sich die einzelnen Attribute des Objects aendern
  69.  
  70.     // Initialisierung und Bekanntmachung des Objects
  71.     Class * initLineClass P((void))
  72.     {
  73.         Class * cl;
  74.  
  75.         // Neue Klasse mit dem Namen "lineclass" bekanntgeben und
  76.         // verschiedene Default-Werte initialisieren.
  77.         if (cl = MakeClass (NULL,
  78.             "lineclass", NULL,
  79.             sizeof (struct LineData),
  80.             0))
  81.         {
  82.         // Dispatcher eintragen. Unter UNIX muss bei h_Entry immer
  83.         // HookEntry stehen.
  84.         cl->cl_Dispatcher.h_Entry    = HookEntry;   // always for UNIX
  85.         cl->cl_Dispatcher.h_SubEntry = dispatchLineClass;
  86.         }
  87.     } // initLineClass
  88.  
  89.  
  90.     // Klasse wieder entfernen. Das muss man vor dem Verlassen
  91.     // des Programms tun, weil zB. unter AmigaOS alle Public-Objecte
  92.     // global bekannt sind und deshalb andere Programme u.U. noch
  93.     // auf das Object zugreifen.
  94.     BOOL freeLineClass (cl)
  95.     Class * cl;
  96.     {
  97.         return (FreeClass (cl));
  98.     } // freeLineClass
  99.  
  100.  
  101.     // Hier folgt jetzt der interessante Teil: Ein BOOSPI-Dispatcher.
  102.     // GETA4 ist unter UNIX leer, unter AmigaOS wird damit die lokale
  103.     // Umgebung (zB. Variablen initialisiert
  104.     __geta4 ULONG dispatchLineClass (cl, o, msg)
  105.     REG(A0) Class  * cl;
  106.     REG(A2) Object * o;
  107.     REG(A1) Msg      msg;
  108.     {
  109.         struct LineData * inst;        // instance data
  110.         APTR          retval = NULL;    // generic return value
  111.  
  112.         // Die Bedeutung von retval haengt von der verwendeten Methode
  113.         // ab. ZB. ist es bei OM_GET ein Boolean-Wert, bei OM_NEW aber
  114.         // ein Zeiger auf das neue Object
  115.  
  116.         switch (msg->MethodID)  // Welche Methode ?
  117.         {
  118.         case OM_NEW:    // Zuerst wird die Message nach "oben"
  119.                 // weitergegeben damit die Superclass
  120.                 // zuerst alles Einrichten kann (zB.
  121.                 // Speicher besorgen).
  122.  
  123.         if (retval = (APTR)DoSuperMethodA (cl, o, msg))
  124.         {
  125.             // Bei der OM_NEW-Methode zeigt der Object-Pointer nicht
  126.             // auf ein Object (wie auch ??). DoSuperMethod() gibt
  127.             // einen Zeiger auf das neu erzeugte Object zurueck.
  128.             // INST_DATA() ist ein Macro aus <intuition/classes.h>
  129.             // welches einen Zeiger auf die Instance-Data des Objects
  130.             // zurueckliefert. Dies ist hier die LineData-Struktur
  131.             // von oben.
  132.             //
  133.             //      Beachten Sie, dass der Speicher in keiner Weise
  134.             // vorinitialisiert wird !
  135.  
  136.             inst = INST_DATA(cl,retval);
  137.  
  138.             // Jetzt koennen wir alle Felder initalisieren. Das muss
  139.             // so getan werden, dass man gefahrlos ALLE Methoden auf
  140.             // das Object anwenden kann.
  141.  
  142.             inst->Width = 0;    // Breite = 0 -> Nichts tun
  143.  
  144.             // Wenn wir hier etwas komplizierteres machen wollten
  145.             // (zB. Kind-Objecte erzeugen) waere das ohne weiteres
  146.             // moeglich. Aber dann muss bei einem Fehler
  147.             // DoMethod (retval, OM_DISPOSE); aufgerufen werden !
  148.         }
  149.  
  150.         // Nur abbrechen, wenn kein Object erzeugt werden konnte.
  151.         // Sonst sollten wir noch die Start-Attribute abfragen !
  152.         if (!retval)
  153.             break;
  154.  
  155.         // Fuer weitere Schritte sollte <o> schon auf einen
  156.         // sinnvollen Wert zeigen :-)
  157.  
  158.         o = (Object *)retval;
  159.  
  160.         case OM_SET:    // Mit OM_SET kann man Attribute setzen.
  161.         case OM_UPDATE: // Wie OM_SET, nur kommt es von einem anderen
  162.                 // BOOPSI-Object !
  163.  
  164.         // Zuerst wieder die SuperClass ranlassen (nur, wenn nicht
  165.         // OM_NEW) damit diese zuerst alle ihr wichtigen Attribute
  166.         // bearbeiten kann.
  167.  
  168.         if (msg->MethodID != OM_NEW)
  169.             retval = DoSuperMethodA (cl, o, msg);
  170.  
  171.         // Jetzt sind wir dran
  172.  
  173.         {   // Fuer lokale Variable
  174.             struct TagItem * ti, * tstate;
  175.  
  176.             // Instance-Data raussuchen
  177.  
  178.             inst = INST_DATA(cl, o);
  179.  
  180.             // Tag-Liste untersuchen und Attribute kopieren
  181.             for (ti=tstate=((struct opSet *)msg)->ops_AttrList);
  182.                 ti; ti = NextTagItem (&tstate))
  183.             {
  184.             // Hier alle unbekannten Tags einfach ignorieren
  185.             // weil sie wahrscheinlich zu einer der Superklassen
  186.             // gehoeren
  187.             switch (ti->ti_Tag)
  188.             {
  189.             case LINE_StartX:
  190.                 *(&inst->coords[0]) = *(FLOAT *)ti->ti_Data;
  191.                 break;
  192.  
  193.             case LINE_StartY:
  194.                 *(&inst->coords[1]) = *(FLOAT *)ti->ti_Data;
  195.                 break;
  196.  
  197.             case LINE_EndX:
  198.                 *(&inst->coords[2]) = *(FLOAT *)ti->ti_Data;
  199.                 break;
  200.  
  201.             case LINE_EndY:
  202.                 *(&inst->coords[3]) = *(FLOAT *)ti->ti_Data;
  203.                 break;
  204.  
  205.             case LINE_Width:
  206.                 inst->Width = ti->ti_Data;
  207.                 break;
  208.  
  209.             case LINE_Style:
  210.                 inst->Style = ti->ti_Data;
  211.                 break;
  212.  
  213.             }
  214.             } // for
  215.         } // local block
  216.  
  217.         break; // OM_SET, OM_UPDATE
  218.  
  219.         case OM_GET: // ein (1!) Attribut lesen
  220.         inst = INST_DATA(cl, o);
  221.  
  222.         // Erst mal auf TRUE setzen -> Attribut gefunden.
  223.         // Wenn es ein Line-Attribut ist, wird es auf alle
  224.         // Faelle gefunden, wenn es ein Attribut der Superclass
  225.         // ist, wird der Wert nochmals bei DoSuperMethodA()
  226.         // gesetzt.
  227.  
  228.         retval = (APTR)TRUE;
  229.  
  230.         switch (((struct opGet *)msg)->opg_AttrID)
  231.         {
  232.         case LINE_StartX:
  233.             *((FLOAT *)(((struct opGet *)msg)->opg_Storage)) =
  234.                 inst->coords[0];
  235.             break;
  236.  
  237.         // usw. usf.
  238.  
  239.         default:
  240.             // Kein Attribut von uns ?? Dann lassen wir mal die
  241.             // Superclass ran
  242.             retval = DoSuperMethodA (cl, o, msg);
  243.         }
  244.  
  245.         break;     // OM_GET
  246.  
  247.         default: // Unbekannte Methode ? Vielleicht kann ja die
  248.              // Superclass was damit anfangen !
  249.  
  250.         // Hier wird in unserem Beispiel OM_DISPOSE behandelt.
  251.         // Sollten wir eine kompliziertere Version von OM_DISPOSE
  252.         // benoetigen, weil wir zB. Kinder freizugeben haben,
  253.         // muessten wird das VOR dem Aufruf von DoSuperMethodA()
  254.         // machen, weil danach der Zugriff auf das Object nicht
  255.         // mehr erlaubt ist.
  256.  
  257.         retval = DoSuperMethodA (cl, o, msg);
  258.         break;
  259.  
  260.         } // switch
  261.  
  262.         // Ergebnis zurueck
  263.         return (retval);
  264.     } // dispatchLineClass
  265.  
  266.     SEE ALSO
  267.  
  268.     INDEX
  269.  
  270.     HISTORY
  271.     14.09.93    ada created
  272.  
  273. *******************************************************************************/
  274.  
  275. /**************************************
  276.         Includes
  277. **************************************/
  278. #ifndef INTUITION_CLASSES_H
  279. #   include <intuition/classes.h>
  280. #endif
  281. #ifndef CLIB_ALIB_PROTOS_H
  282. #   include <clib/alib_protos.h>
  283. #endif
  284. #include <stdarg.h>
  285.  
  286.  
  287. static ULONG CallHookPkt (struct Hook * hook, APTR object, APTR paramPacket)
  288. {
  289.     return ((*(hook->h_Entry)) (hook, object, paramPacket));
  290. }
  291.  
  292. /******************************************************************************
  293.  
  294.     NAME */
  295.     ULONG DoMethodA (
  296.  
  297. /*  SYNOPSIS */
  298.     Object * obj,
  299.     Msg     message)
  300.  
  301. /*  FUNCTION
  302.     Wendet eine Methode auf ein BOOPSI-Object an. Dazu wird der Dispatcher
  303.     fuer die Klasse, der das Object angehoert aufgerufen. Die Methoden,
  304.     welche ein Object unterstuetzt, werden auf einer Klasse-fuer-Klasse
  305.     Basis definiert.
  306.  
  307.     INPUTS
  308.     obj - Das Object, auf welches sich die Operation bezieht.
  309.     message - Die Method-Message. Das erste ULONG der Message definiert den
  310.         Typ, der Rest haengt von der Klasse ab.
  311.  
  312.     RESULT
  313.     Der Rueckgabewert haengt von der Methode ab. Bei OM_NEW ist es z.B. ein
  314.     Zeiger auf das neu generierte Object; andere Methoden verwenden andere
  315.     Ergebnis-Werte. Diese werden bei der Beschreibung der Klasse definiert
  316.     und sind dort nachzulesen.
  317.  
  318.     NOTES
  319.  
  320.     EXAMPLE
  321.  
  322.     BUGS
  323.  
  324.     SEE ALSO
  325.     NewObject(), SetAttrs(), GetAttr(), DisposeObject(), DoSuperMethod(),
  326.     "Basic Object-Oriented Programming System for Intuition" und das
  327.     "boopsi Class Reference" Dokument.
  328.  
  329.     HISTORY:
  330.     14.09.93    ada created
  331.  
  332. ******************************************************************************/
  333. {
  334.     return (CallHookPkt ((struct Hook *)OCLASS(obj), obj, message));
  335. } /* DoMethodA */
  336.  
  337.  
  338. ULONG DoMethod (Object * obj, ULONG MethodID, ...)
  339. {
  340.     va_list args;
  341.     ULONG   retval;
  342.  
  343.     va_start (args, MethodID);
  344.  
  345.     retval = (CallHookPkt ((struct Hook *)OCLASS(obj), obj, (Msg)&MethodID));
  346.  
  347.     va_end (args);
  348.  
  349.     return (retval);
  350. } /* DoMethod */
  351.  
  352.  
  353. /******************************************************************************
  354.  
  355.     NAME
  356.     DoSuperMethodA -- Sende eine Message an die SuperClass eines Objects
  357.  
  358.     SYNOPSIS
  359.     retval = DoSuperMethodA (cl, obj, message)
  360.  
  361.     ULONG DoSuperMethodA (Class *, Object * obj, Msg message);
  362.  
  363.     retval = DoSuperMethod (class, obj, MethodID, ...)
  364.  
  365.     ULONG DoSuperMethod (Class *, Object * obj, ULONG MethodID, ...);
  366.  
  367.     FUNCTION
  368.     Sendet eine BOOPSI-Message an ein BOOPSI-Object als ob dieses eine
  369.     Instanz seiner SuperKlasse waere.
  370.  
  371.     INPUTS
  372.     cl - Class des Objects.
  373.     obj - Das Object, auf welches sich die Operation bezieht.
  374.     message - Die Method-Message. Das erste ULONG der Message definiert den
  375.         Typ, der Rest haengt von der Klasse ab.
  376.  
  377.     RESULT
  378.     Der Rueckgabewert haengt von der Methode ab. Bei OM_NEW ist es z.B. ein
  379.     Zeiger auf das neu generierte Object; andere Methoden verwenden andere
  380.     Ergebnis-Werte. Diese werden bei der Beschreibung der Klasse definiert
  381.     und sind dort nachzulesen.
  382.  
  383.     NOTES
  384.  
  385.     EXAMPLE
  386.  
  387.     BUGS
  388.  
  389.     SEE ALSO
  390.     NewObject(), SetAttrs(), GetAttr(), DisposeObject(), DoMethod(),
  391.     "Basic Object-Oriented Programming System for Intuition" und das
  392.     "boopsi Class Reference" Dokument.
  393.  
  394.     HISTORY:
  395.     14.09.93    ada created
  396.  
  397. ******************************************************************************/
  398.  
  399. ULONG DoSuperMethodA (cl, obj, message)
  400. Class  * cl;
  401. Object * obj;
  402. Msg     message;
  403. {
  404.     return (CallHookPkt ((struct Hook *)cl->cl_Super, obj, message));
  405. } /* DoSuperMethodA */
  406.  
  407.  
  408. ULONG DoSuperMethod (Class * cl, Object * obj, ULONG MethodID, ...)
  409. {
  410.     va_list args;
  411.     ULONG   retval;
  412.  
  413.     va_start (args,MethodID);
  414.  
  415.     retval = DoSuperMethodA (cl, obj, (Msg)&MethodID);
  416.  
  417.     va_end (args);
  418.  
  419.     return (retval);
  420. } /* DoSuperMethod */
  421.  
  422.  
  423. #ifdef TODO
  424. /******************************************************************************
  425.  
  426.     NAME
  427.     GetAttrsA
  428.  
  429.     SYNOPSIS
  430.     GetAttr (object, tags)
  431.  
  432.     void GetAttr (Object *, struct TagItem *);
  433.  
  434.     FUNCTION
  435.     Fragt bei dem angegebenen Objekt die angegebenen Attribut ab.
  436.  
  437.     Im ti_Data_feld der TagItem-Elemente werden Zeiger auf Langworte
  438.     erwartet. In diese wird der Wert des Attributs geschrieben.
  439.  
  440.     Nicht alle Attribute werden auf diese Attribute reagieren. Welche
  441.     das es tun steht bei der Dokumentation der Klasse.
  442.  
  443.     INPUTS
  444.     object - Das Objekt ueber dessen Attribut wir uns informieren wollen
  445.     tags - Gesuchtes Attribut und hier wird die Antwort reingeschrieben.
  446.  
  447.     RESULT
  448.     Keines.
  449.  
  450.     NOTES
  451.     Diese Funktion ruft die OM_GET-Methode fuer ein Objekt auf.
  452.  
  453.     EXAMPLE
  454.  
  455.     BUGS
  456.  
  457.     SEE ALSO
  458.     NewObject(), DisposeObject(), SetAttr(), GetAttrs(), MakeClass(),
  459.     "Basic Object-Oriented Programming System for Intuition" und das
  460.     "boopsi Class Reference" Dokument.
  461.  
  462.     HISTORY:
  463.     02.12.93    ada created
  464.  
  465. ******************************************************************************/
  466.  
  467. void GetAttrsA (object, tags)
  468. Object * object;
  469. struct TagItem * tags;
  470. {
  471.     struct TagItem * ti, * tstate;
  472.  
  473.     /* Fuer alle Attribute in der Liste GetAttr() aufrufen */
  474.     for (ti=tstate=tags; ti; ti = NextTagItem (&tstate))
  475.     {
  476.     GetAttr (ti->ti_Tag, object, (ULONG *) ti->ti_Data);
  477.     }
  478. } /* GetAttrsA */
  479.  
  480.  
  481. void GetAttrs (Object * obj, ...)
  482. {
  483.     va_list         args;
  484.  
  485.     va_start (args, obj);
  486.  
  487.     GetAttrsA (obj, (struct TagItem *)args);
  488.  
  489.     va_end (args);
  490. } /* GetAttrs */
  491. #endif
  492.  
  493.  
  494. /*******************************************************************************
  495. *****  ENDE boopsi.c
  496. *******************************************************************************/
  497.