IMPLEMENTATION MODULE PortUtils;

(** ------------------------------------------------------------------

                 Commodore Amiga port utilities module

      (c) Copyright 1986 Modula-2 Software Ltd.  All Rights Reserved
      (c) Copyright 1986 TDI Software, Inc.      All Rights Reserved

    ------------------------------------------------------------------ **)


(* VERSION FOR COMMODORE AMIGA

     Original Author : Paul Curtis, Modula-2 Software Ltd.  16-Dec-85

     Version         : 0.01a  27-May-86  Paul Curtis, Modula-2 Software Ltd.
                         Added Create/Delete Std/Ext IO.
                       0.00a  16-Dec-85  Paul Curtis, Modula-2 Software Ltd.
                         Original

  *)


  (*$S-*)(*$T-*)


  FROM SYSTEM IMPORT TSIZE, BYTE, ADR, ADDRESS, NULL;
  FROM Lists IMPORT NewList;
  FROM Nodes IMPORT NTMsgPort, NTMessage;
  FROM IO IMPORT IOStdReq, IOStdReqPtr, IORequestPtr;
  FROM Ports IMPORT MsgPortPtr, MsgPort, MsgType, AddPort, RemPort;
  FROM Memory IMPORT AllocMem, FreeMem, MemPublic, MemClear, MemReqSet;
  FROM Tasks IMPORT FindTask, MyTask, AllocSignal, FreeSignal, AnySignal,
    NoSignals, SIGNAL;

  PROCEDURE CreatePort(VAR name: ARRAY OF CHAR; pri: INTEGER): MsgPortPtr;
    (* create a message port. *)
  VAR
    port: MsgPortPtr;
    sigBit: SIGNAL;
  BEGIN
    sigBit := AllocSignal(AnySignal);
    IF sigBit = NoSignals THEN RETURN NULL END;                 (*0.01a*)
    port := AllocMem(SIZE(port^),MemReqSet{MemPublic, MemClear});
    IF port = NULL THEN                                         (*0.01a*)
      FreeSignal(sigBit);
      RETURN NULL                                               (*0.01a*)
    END;
    WITH port^ DO
      WITH mpNode DO
        IF name[0] = 0C THEN lnName := NULL                     (*0.01a*)
        ELSE lnName := ADR(name)                                (*0.01a*)
        END;
        lnPri := BYTE(pri);
        lnType := BYTE(NTMsgPort)
      END;
      mpFlags := PASignal;
      mpSigBit := BYTE(sigBit);
      mpSigTask := FindTask(MyTask)
    END;
    IF name[0] # 0C THEN AddPort(port)
    ELSE NewList(ADR(port^.mpMsgList))
    END;
    RETURN port
  END CreatePort;


  PROCEDURE DeletePort(port: MsgPortPtr);
    (* delete a message port *)
  BEGIN
    WITH port^ DO
      WITH mpNode DO
        IF lnName # NULL THEN RemPort(port) END;
        lnType := BYTE(0FFH); (* unknown to Exec *)
        mpMsgList.lhHead := NIL;
      END;
      FreeSignal(SIGNAL(mpSigBit));
    END;
    FreeMem(port,SIZE(port^))
  END DeletePort;

  PROCEDURE CreateStdIO(port: MsgPortPtr): IOStdReqPtr;
    (* create a standard IO request. *)
  BEGIN
    RETURN IOStdReqPtr(CreateExtIO(port,TSIZE(IOStdReq)))
  END CreateStdIO;

  
  PROCEDURE DeleteStdIO(ioReq: IOStdReqPtr);
    (* return memory allocated for IO request. *)
  BEGIN
    DeleteExtIO(IORequestPtr(ioReq),SIZE(ioReq^))
  END DeleteStdIO;
  

  PROCEDURE CreateExtIO(port: MsgPortPtr; size: LONGCARD): IORequestPtr;
    (* create an extended IO request. *)
  VAR ioReq: IORequestPtr;
  BEGIN
    IF port = NULL THEN RETURN NULL
    ELSE
      ioReq := AllocMem(size,MemReqSet{MemClear,MemPublic});
      IF ioReq # NULL THEN
        WITH ioReq^.ioMessage DO
          mnNode.lnType := BYTE(NTMessage);
          mnNode.lnPri := BYTE(0);
          mnLength := CARDINAL(size);
          mnReplyPort := port;
        END
      END;
      RETURN ioReq
    END
  END CreateExtIO;

  PROCEDURE DeleteExtIO(ioReq: IORequestPtr; size: LONGCARD);
    (* return memory allocated for extended IO request. *)
  BEGIN
    WITH ioReq^ DO
      ioMessage.mnNode.lnType := BYTE(0FFH);
      ioDevice := NIL;
      ioUnit := NIL;
    END;
    FreeMem(ioReq,size);
  END DeleteExtIO;


(*$P-*)


END PortUtils.
