(*---------------------------------------------------------------------------
  :Program.    MultiNotify
  :Author.     Thomas Igracki
  :Address.    Obstallee 45, 1000 Berlin 20, W-Germany
  :E-Mail.     T.IGRACKI@BAMP.ZER
  :Version.    V1.21
  :Date.       27-Apr-92
  :Copyright.  Me
  :Language.   Oberon
  :Translator. Amiga Oberon 2.13d
  :Contents.   Modul zur Unterstützung von _mehreren_ Notifies.
  :History.    V1.2: EndNotify (name: ARRAY OF CHAR) zum vorzeitigen Beenden
  :History.    V1.2: eines bestimmten Notifies.
  :History.    V1.21:Bug in StartNotify() behoben! (Dank an HARTMUT@ASN.ZER!)
  :History.    V1.21:Speicher vom NotifyNode wird DISPOSEd, bei Fehler
  :History.    V1.21:Neue Prozedur zum vorzeitigen Löschen _aller_ Notifies!
  :Usage.      IMPORT MultiNotify
  :Remark.     OS2.0 Only!
  :Remark.     Bei >= V2.14 des OberonCompilers, kann man sich das neudefinieren
  :Remark.     der NotifyRequest Struktur und der StartNotify() und EndNotify()
  :Remark.     Prozeduren sparen (siehe auch Kommentare)!
---------------------------------------------------------------------------*)

MODULE MultiNotify;
IMPORT
  s: SYSTEM, d: Dos, e: Exec, l: Lists;
TYPE
(* NotifyRequest nochmal definiert, da sie in Dos.mod falsch definiert ist! *)
(* Nur bei < V2.14 des OberonCompilers! *)
  NotifyRequest * = STRUCT
    name * : e.STRPTR;
    fullName * : e.STRPTR;           (* set by dos - don't touch *)
    userData * : LONGINT;            (* for applications use *)
    flags * : LONGSET;

    (* port * : e.MsgPortPtr; das war der Fehler! *)

    task * : e.TaskPtr;              (* could also be: port * : e.MsgPortPtr *)
    signalNum * : SHORTINT;
    pad1,pad2,pad3: SHORTINT;

    reserved * : ARRAY 4 OF LONGINT; (* leave 0 for now *)

    (* internal use by handlers *)
    msgCount * : LONGINT;            (* # of outstanding msgs *)
    handler  * : e.MsgPortPtr;       (* handler sent to (for EndNotify) *)
  END;

  NotifyNode = RECORD(l.Node) not: NotifyRequest END;
  NotifyNodePtr = POINTER TO NotifyNode;
VAR
   dos       : d.DosLibraryPtr; (* Nur bei < V2.14 des OberonCompilers! *)
   NotifyList: l.List;
   NodePtr   : l.NodePtr;

(* Die nächsten beiden Prozeduren nur bei < V2.14 des OberonCompilers! *)
PROCEDURE DosStartNotify {dos,-888}(VAR notify{1}: NotifyRequest): BOOLEAN;
PROCEDURE DosEndNotify   {dos,-894}(VAR notify{1}: NotifyRequest);

(* Das Signal wird zurückgegeben, oder -1 wenn was falsch lief *)
PROCEDURE StartNotify* (name: ARRAY OF CHAR): SHORTINT; (* $CopyArrays- *)
VAR nn: NotifyNodePtr;
BEGIN
     NEW(nn); IF nn = NIL THEN RETURN -1 END;
     nn.not.name := s.ADR(name); nn.not.flags := LONGSET{d.sendSignal};
     nn.not.task := e.exec.thisTask; nn.not.signalNum := e.AllocSignal(-1);
     IF nn.not.signalNum = -1 THEN DISPOSE(nn); RETURN -1 END;
     IF DosStartNotify (nn.not) THEN
	l.AddTail (NotifyList,nn); RETURN nn.not.signalNum
     ELSE
        e.FreeSignal(nn.not.signalNum); DISPOSE(nn); RETURN -1
     END
END StartNotify;

PROCEDURE EndNotify* (name: ARRAY OF CHAR); (* $CopyArrays- *)
VAR found: BOOLEAN;
BEGIN
     IF ~l.Empty(NotifyList) THEN
        NodePtr := l.Head(NotifyList);
        REPEAT
           found := NodePtr(NotifyNode).not.name^ = name
        UNTIL found OR ~l.Next(NodePtr);
        IF found THEN
	   DosEndNotify (NodePtr(NotifyNode).not);
	   e.FreeSignal (NodePtr(NotifyNode).not.signalNum);
           l.Remove (NotifyList,NodePtr);
	   DISPOSE (NodePtr)
        END
     END
END EndNotify;

PROCEDURE EndAllNotifies*;
BEGIN
    (* Notify-Liste löschen und Notifier beenden*)
     WHILE ~l.Empty (NotifyList) DO
	DosEndNotify (NodePtr(NotifyNode).not);
	e.FreeSignal (NodePtr(NotifyNode).not.signalNum);
	NodePtr := l.RemHead (NotifyList);
        DISPOSE (NodePtr)
     END;
END EndAllNotifies;

BEGIN
     dos := d.dos; (* Nur bei < V2.14 des OberonCompilers! *)
     l.Init (NotifyList)
CLOSE
     EndAllNotifies
END MultiNotify.
