(* ------------------------------------------------------------------------
  :Program.       BlackMagicVA.mod
  :Contents.      var args interface for several BlackMagic functions
  :Author.        Franz Schwarz
  :Copyright.     Giftware (Freely distributable, yet copyrighted software.
  :Copyright.     If you like this magnificent;-) piece of software, you
  :Copyright.     are encouraged to send the author a present, a nice
  :Copyright.     postcard, money, or something else pleasing the author.)
  :Copyright.     Free use in Freely Distributable stuff (but gimme credit)
  :Copyright.     Explicit confirmation needed for use in commercial code
  :Language.      Oberon-2
  :Translator.    Amiga Oberon 3.00
  :History.       BlackMagicVM.mod 1.5 (20.7.93) [fSchwarz] initial release
  :History.       1.6 (25.7.93) [fSchwarz] no changes (only in BlackMagic)
  :History.       1.7 (27.7.93) [fSchwarz] fixed BlackMagicVA <-> BlackMagic 
  :History.         layout
  :History.       1.8 (6.8.93) [fSchwarz] no changes (only in BlackMagic)
  :History.       1.9 (9.8.93) [fSchwarz] no changes (only in BlackMagic)
  :History.       1.10 (14.8.93) [fSchwarz] no changes (only in BlackMagic)
  :History.       1.11 (22.9.93) [fSchwarz] no changes (only in BlackMagic)
  :History.       1.12 (30.9.93) [fSchwarz] adapted to OS3.0 interface
  :History.         modules by hartmut Goebel; changes in BlackMagic)
  :Address.       Mühlenstraße 2, D-78591 Durchhausen, Germany / R.F.A.
  :Address.       uucp: Franz.Schwarz@mil.ka.sub.org; Fido: 2:241/7506.18
  :Remark.        Requires OS3.0 interface modules update by hartmut Goebel
  :Remark.        As of Amiga Oberon Release 3.00: possible odd pointers to
  :Remark.        array of char/byte: _don't_ compile with OddChk. The
  :Remark.        compiler's options stack is broken as of Amiga-Oberon 3.00
--------------------------------------------------------------------------- *)

(* $SET NODEBUG *)

(****** BlackMagicVA/--overview-- ***********************************************
*
*       BlackMagicVA (VA is an acronym for Var Args) is a module that offers 
*   var args interfaces for several of BlackMagic's functions. These varargs
*   interfacing functions have been extracted from the BlackMagic module
*   because of the special fake library technique that is necessary for
*   implementing var args functions in Amiga-Oberon. Due to this technique,
*   all varargs functions are always linked to all programs that import
*   BlackMagicVA.
*
*****************************************************************************)

MODULE BlackMagicVA;

IMPORT 
  bm: BlackMagic, e: Exec, d: Dos, I: Intuition, u: Utility, 
  loc: Locale, o: OberonLib, y: SYSTEM
  (* $IF DEBUG *) , NoGuru (* $END *) 
  ;

TYPE
  FakeBasePtr = UNTRACED POINTER TO FakeBase;

  FakeBase = STRUCT
    code1: LONGINT;
    jmp1 : e.PROC;
    code2: LONGINT;
    jmp2 : e.PROC;
    a5   : e.APTR;
    code3: LONGINT;
    jmp3 : e.PROC;
    code4: LONGINT;
    jmp4 : e.PROC;
    code5: LONGINT;
    jmp5 : e.PROC;
  END;
  
CONST
  fkBase = FakeBase (4E714EF9H, NIL, 4E714EF9H, NIL, NIL, 
                     4E714EF9H, NIL, 4E714EF9H, NIL, 4E714EF9H, NIL);
                 (* nop                *
                  * jmp    0x00000000  *
                  * nop                *
                  * jmp    0x00000000  *
                  * dc.l   0x00000000  *
                  * nop                *
                  * jmp    0x00000000  *
                  * nop                *
                  * jmp    0x00000000  *
                  * nop                *
                  * jmp    0x00000000  *)

VAR
  FkBase : FakeBasePtr;
  FkBaseS: FakeBase;

PROCEDURE SPrintf * {FkBase, 0} (buffer{11}: ARRAY OF CHAR;
                                 format{8} : ARRAY OF CHAR;
                                 args{9}.. : e.APTR        ): LONGINT;

PROCEDURE SPrintF * {FkBase, 0} (buffer{11}: ARRAY OF CHAR;
                                 format{8} : ARRAY OF CHAR;
                                 args{9}.. : e.APTR        );

PROCEDURE VSPrintf * {FkBase, 0} (buffer{11}: ARRAY OF CHAR;
                                  format{8} : ARRAY OF CHAR;
                                  args{9}   : e.APTR        ): LONGINT;

PROCEDURE VSPrintF * {FkBase, 0} (buffer{11}: ARRAY OF CHAR;
                                  format{8} : ARRAY OF CHAR;
                                  args{9}   : e.APTR        );

PROCEDURE SPrintFInternal();
(* $EntryExitCode- *)                             
BEGIN

  y.INLINE (048E7U,00032U,04FEFU,0FFF8U,02F4BU,00004U,04297U,0264FU,
            045FAU,0001AU,02C79U,00000U,00004U,04EAEU,0FDF6U,02017U,
            04FEFU,00008U,04CDFU,04C00U,05380U,04E75U,02F0CU,05293U,
            04AABU,00004U,0670AU,0286BU,00004U,01880U,052ABU,00004U,
            0285FU,04E75U                                           );



(*
 * 00.00000000  48e7 0032                 MOVEM.L A2-A3/A6,-(A7)
 * 00.00000004  4fef fff8                 LEA.L   fff8(A7),A7
 * 00.00000008  2f4b 0004                 MOVE.L  A3,0004(A7)
 * 00.0000000c  4297                      CLR.L   (A7)
 * 00.0000000e  264f                      MOVEA.L A7,A3
 * 00.00000010  45fa 001a                 LEA.L   002c(pc),A2
 * 00.00000014  2c79 0000 0004            MOVEA.L 00000004,A6
 * 00.0000001a  4eae fdf6                 JSR     fdf6(A6)
 * 00.0000001e  2017                      MOVE.L  (A7),D0
 * 00.00000020  4fef 0008                 LEA.L   0008(A7),A7
 * 00.00000024  4cdf 4c00                 MOVEM.L (A7)+,A2-A3/A6
 * 00.00000028  5380                      SUBQ.L  #1,D0
 * 00.0000002a  4e75                      RTS
 * 00.0000002c  2f0c                      MOVE.L  A4,-(A7)
 * 00.0000002e  5293                      ADDQ.L  #1,(A3)
 * 00.00000030  4aab 0004                 TST.L   0004(A3)
 * 00.00000034  670a                      BEQ.B   00000040
 * 00.00000036  286b 0004                 MOVEA.L 0004(A3),A4
 * 00.0000003a  1880                      MOVE.B  D0,(A4)
 * 00.0000003c  52ab 0004                 ADDQ.L  #1,0004(A3)
 * 00.00000040  285f                      MOVEA.L (A7)+,A4
 * 00.00000042  4e75                      RTS
 *)

END SPrintFInternal;



PROCEDURE DynAppendFmtInternal (dstr{8}  : UNTRACED POINTER TO bm.DynStrPtr;
                                format{9}: bm.LongStrPtr;
                                args{10} : e.APTR;
                                base{14} : FakeBasePtr                 ): BOOLEAN;
(* $StackChk- $SaveRegs+ *)
BEGIN
  y.SETREG (13, base.a5);
  IF format = NIL THEN RETURN FALSE; END;
  RETURN bm.VDynAppendFmt (dstr^, format^, args);
END DynAppendFmtInternal;
(* $StackChk= *)

PROCEDURE DynAppendFmt * {FkBase, 8} (VAR dstr{8}: bm.DynStrPtr;
                                      format{9}  : ARRAY OF CHAR;
                                      args{10}.. : e.APTR        ): BOOLEAN;

PROCEDURE DSPrintf * {FkBase, 8} (VAR dstr{8}: bm.DynStrPtr;
                                  format{9}  : ARRAY OF CHAR;
                                  args{10}.. : e.APTR        ): BOOLEAN;

PROCEDURE VDynAppendFmt * {FkBase, 8} (VAR dstr{8}: bm.DynStrPtr;
                                       format{9}  : ARRAY OF CHAR;
                                       args{10}   : e.APTR        ): BOOLEAN;

PROCEDURE VDSPrintf * {FkBase, 8} (VAR dstr{8}: bm.DynStrPtr;
                                   format{9}  : ARRAY OF CHAR;
                                   args{10}   : e.APTR        ): BOOLEAN;

PROCEDURE DynFmtLocaleInternal (dstr{1}   : UNTRACED POINTER TO bm.DynStrPtr;
                                locale{2} : loc.LocalePtr;
                                format{8} : bm.LongStrPtr;
                                args{3}   : e.APTR;
                                base{14}  : FakeBasePtr                 ): BOOLEAN;
VAR 
  dstr1: UNTRACED POINTER TO bm.DynStrPtr;                                
(* $SaveRegs+ $StackChk- *)
BEGIN
  dstr1 := dstr;
  y.SETREG (13, base.a5);
  IF format = NIL THEN RETURN FALSE; END;
  RETURN bm.VDynFmtLocale (dstr1^, locale, format^, args);
END DynFmtLocaleInternal;
(* $StackChk= *)  

PROCEDURE DynFmtLocale * {FkBase, 20} (VAR dstr{1}: bm.DynStrPtr;
                                       locale{2}  : loc.LocalePtr;
                                       format{8}  : ARRAY OF CHAR;
                                       args{3}..  : e.APTR        ): BOOLEAN;

PROCEDURE VDynFmtLocale * {FkBase, 20} (VAR dstr{1}: bm.DynStrPtr;
                                        locale{2}  : loc.LocalePtr;
                                        format{8}  : ARRAY OF CHAR;
                                        args{3}    : e.APTR        ): BOOLEAN;

PROCEDURE FLPrintfInternal (fh{1}     : d.FileHandlePtr;
                            locale{2} : loc.LocalePtr;
                            format{8} : bm.LongStrPtr;
                            args{3}   : e.APTR;
                            base{14}  : FakeBasePtr     ): BOOLEAN;
VAR                            
  fh1: e.APTR;
(* $SaveRegs+ $StackChk- *)
BEGIN
  fh1 := fh;
  y.SETREG (13, base.a5);
  IF format = NIL THEN RETURN FALSE; END;
  RETURN bm.VFLPrintf (fh1, locale, format^, args);
END FLPrintfInternal;
(* $StackChk= *)  

PROCEDURE FLPrintf * {FkBase, 36} (fh{1}      : d.FileHandlePtr;
                                   locale{2}  : loc.LocalePtr;
                                   format{8}  : ARRAY OF CHAR;
                                   args{3}..  : e.APTR        ): BOOLEAN;

PROCEDURE FLPrintF * {FkBase, 36} (fh{1}      : d.FileHandlePtr;
                                   locale{2}  : loc.LocalePtr;
                                   format{8}  : ARRAY OF CHAR;
                                   args{3}..  : e.APTR        );

PROCEDURE VFLPrintf * {FkBase, 36} (fh{1}      : d.FileHandlePtr;
                                    locale{2}  : loc.LocalePtr;
                                    format{8}  : ARRAY OF CHAR;
                                    args{3}    : e.APTR        ): BOOLEAN;


PROCEDURE SimpleRequestInternal (win{1}    : I.WindowPtr;
                                 flags{2}  : LONGSET;
                                 title{3}  : bm.LongStrPtr;
                                 txtfmt{8} : bm.LongStrPtr;
                                 gadfmt{9} : bm.LongStrPtr;
                                 args{4}   : e.APTR;
                                 base{14}  : FakeBasePtr): LONGINT;
VAR  
  win1: e.APTR;
  cha : ARRAY 1 OF CHAR;
(* $SaveRegs+ $StackChk- *)
BEGIN  
  win1 := win;
  y.SETREG (13, base.a5);
  IF (txtfmt = NIL) OR (gadfmt = NIL) THEN RETURN NIL; END;
  IF title = NIL THEN 
    INCL (flags, bm.ignoreTitle); title := bm.StrIndex (cha, 0);
  END;
  RETURN bm.SimpleRequestArgs (win1, flags, title^, txtfmt^, gadfmt^, args);
END SimpleRequestInternal;
(* $StackChk= *)  

PROCEDURE SimpleRequest * {FkBase, 28} (win{1}    : I.WindowPtr;
                                        flags{2}  : LONGSET;
                                        title{3}  : ARRAY OF CHAR;
                                        txtfmt{8} : ARRAY OF CHAR;
                                        gadfmt{9} : ARRAY OF CHAR;
                                        args{4}.. : e.APTR        ): LONGINT;
                                        
PROCEDURE SimpleRequestArgs * {FkBase, 28} (win{1}    : I.WindowPtr;
                                            flags{2}  : LONGSET;
                                            title{3}  : ARRAY OF CHAR;
                                            txtfmt{8} : ARRAY OF CHAR;
                                            gadfmt{9} : ARRAY OF CHAR;
                                            args{4}   : e.APTR        ): LONGINT;

BEGIN
  IF u.base = NIL THEN HALT (20); END;
  FkBaseS := fkBase;
  FkBase := y.ADR (FkBaseS);
  FkBase.jmp1 := SPrintFInternal;
  FkBase.jmp2 := y.VAL (e.PROC, DynAppendFmtInternal);
  FkBase.jmp3 := y.VAL (e.PROC, DynFmtLocaleInternal);
  FkBase.jmp5 := y.VAL (e.PROC, FLPrintfInternal);
  FkBase.jmp4 := y.VAL (e.PROC, SimpleRequestInternal);
  FkBase.a5 := y.REG (13);
  e.CacheClearU();

CLOSE
  (* nop *)
END BlackMagicVA.
