
; :Program.       Printf
; :Author.        Volker Rudolph
; :Address.       Medicusstr. 31 / 6750 Kaiserslautern
; :Phone.         0631/17160
; :ShortCut.      [vor]
; :Support.       Bernd Preusing (DisObject)
; :Version.       1.2
; :Date.          25.6.1989
; :Copyright.     PD
; :Language.      Assembler / Modula-II
; :Translator.    Asm68k V1.1.0 (PD) / M2Amiga 3.2d
; :Imports.       Nichts !!!
; :Contents.      Allzweck-Textausgabe in Form der C-Funktion Printf.
; :Usage.         Aufruf und Parameter wie in C.

_LVORawDoFmt EQU -522            ; Exec.RawDoFmt
_LVOWrite    EQU -48             ; Dos.Write
_LVOOutput   EQU -60             ; Dos.Output

StkChk       EQU -18             ; Arts.StkChk
Assert       EQU -54             ; Arts.Assert

bufSize      EQU  120            ; siehe Definition-Modul
writeHandle  EQU -130            ; Ausgabe-Handle

  SECTION Module,CODE

  dc.l 1  ; Kennung: .obj-File
  dc.w 1  ; mod
  dc.b 'Printf'
  ds.b 26
  dc.w $1085,$0517,$038F

; CodeSize
  dc.l    ENDE-Prog
; VarSize
  dc.l    130
; ConstSize
  dc.l    Jumps-Consts
; Jumps
  dc.l    16
; Modules
  dc.l    2

Consts:

Jumps:
  dc.w    $4EF9
  dc.l    SPrintf6-132
  dc.w    $4EF9
  dc.l    SPrintf5-132
  dc.w    $4EF9
  dc.l    SPrintf4-132
  dc.w    $4EF9
  dc.l    SPrintf3-132
  dc.w    $4EF9
  dc.l    SPrintf2-132
  dc.w    $4EF9
  dc.l    SPrintf1-132
  dc.w    $4EF9
  dc.l    SPrintf0-132
  dc.w    $4EF9
  dc.l    Printf6-132
  dc.w    $4EF9
  dc.l    Printf5-132
  dc.w    $4EF9
  dc.l    Printf4-132
  dc.w    $4EF9
  dc.l    Printf3-132
  dc.w    $4EF9
  dc.l    Printf2-132
  dc.w    $4EF9
  dc.l    Printf1-132
  dc.w    $4EF9
  dc.l    Printf0-132
  dc.w    $4EF9
  dc.l    WriteToOutput-132
  dc.w    $4EF9
  dc.l    Main-132

ModuleIds:
  dc.w 1  ; mod
  dc.b 'Arts'
  ds.b 28
  dc.w $0F97,$04DA,$0974

  dc.w 2  ; library
  dc.b 'dos.library'
  ds.b 21
  dc.w    0
  dc.l    33

Prog:

dataPtr EQU Prog-12
ArtsBs_ EQU Prog-8
dos_lBs EQU Prog-4

;--------------------------------------------------------------------

SPrintf0:
  moveq   #0,d7
  bra.s   SPrintf
SPrintf1:
  moveq   #1,d7
  bra.s   SPrintf
SPrintf2:
  moveq   #2,d7
  bra.s   SPrintf
SPrintf3:
  moveq   #3,d7
  bra.s   SPrintf
SPrintf4:
  moveq   #4,d7
  bra.s   SPrintf
SPrintf5:
  moveq   #5,d7
  bra.s   SPrintf
SPrintf6:
  moveq   #6,d7
;  bra.s   SPrintf

;--------------------------------------------------------------------

; Register-Belegungen

OFFS     EQUR d6                 ; Gesamtlänge der val-Parameter
HIGHS    EQUR d4                 ; HIGH(str)
INDEX    EQUR d3                 ; INDEX für diverse dbra-Schleifen

HELP     EQUR a4                 ; Hilfs-Pointer
HELP2    EQUR a5

; Register-Parameter (werden vom Rufer übergeben)
ARGC     EQUR d7                 ; Anzahl val-Parameter

HIGHB    EQUR d5                 ; Größe des Ausgabe-Puffers
BUFFER   EQUR a3                 ; Addresse des Ausgabe-Puffers

; Parameter für RawDoFmt
;BUFFER   EQUR a3 ;              ; Puffer (schon mal definiert)
PROC     EQUR a2                 ; Ausgabe-Prozedur für Zeichen
ARGV     EQUR a1                 ; Argument-Vektor
STR      EQUR a0                 ; Format-String

bs       EQU  92                 ; ASCII-Code Backslash '\'

  ; d7 = Anzahl val-Parameter
  ; d5 = HIGH(Buffer)
  ; a3 = ADR(Buffer)

SPrintf:
  movem.l a4/a5,-(sp)            ; a4/a5 retten
  lea     12(a7),HELP            ; Anfang val-Parameter

  move.l  ARGC,OFFS              ; Offset über val-Paramter berechnen
  lsl.l   #2,OFFS

  move.l  12(a7,OFFS),STR        ; str (Format-String)
  move.l  16(a7,OFFS),HIGHS      ; HIGH(str)
  move.l  20(a7,OFFS),BUFFER     ; buffer
  move.l  24(a7,OFFS),HIGHB      ; HIGH(buf)

stackCheck:
  move.l  OFFS,d0                ; Stackbedarf berechnen
  add.l   HIGHS,d0
  addq.l  #3,d0
  neg.l   d0
  movem.l STR/HIGHS/BUFFER/HIGHB/ARGC/OFFS,-(sp)
  move.l  ArtsBs_(pc),a6
  jsr     StkChk(a6)             ; Arts.StkChk
  movem.l (sp)+,STR/HIGHS/BUFFER/HIGHB/ARGC/OFFS
  tst.l   ARGC
  beq.s   copyStr

copyArgs:                        ; val-Argumente auf Stack kopieren
  subq.l  #1,ARGC                ; Sie liegen für die RawDoFmt-Routine
1$:                              ; in der falschen Reihenfolge auf dem
  move.l  (HELP)+,-(sp)          ; Stack.
  dbra    ARGC,1$

  move.l  sp,ARGV                ; Neuer Argument-Vektor

copyStr:                         ; str kopieren,da RawDoFmt eine null
                                 ; am Stringende verlangt
  move.l  HIGHS,INDEX            ; Laenge für str-Kopie
  addq.l  #3,HIGHS
  bclr    #0,HIGHS               ; auf gerade Zahl abrunden
  sub.l   HIGHS,sp               ; Platz machen

  move.l  STR,HELP               ; kopieren von
  move.l  sp,HELP2               ; nach
  move.l  sp,STR                 ; Neue Adresse des Format-Strings
1$:
  move.b  (HELP)+,(HELP2)+       ; Kopieren
  dbra    INDEX,1$
  move.b  #0,(HELP2)             ; Format-String mit null (0C) beenden

  lea     Backslash(pc),HELP     ; Backslash-Flag auf FALSE setzen
  clr.b   (HELP)

  lea     BufEnd(pc),HELP        ; Endadresse des Puffers berechnen
  move.l  BUFFER,(HELP)
  add.l   HIGHB,(HELP)

  lea     PutChProc(pc),PROC     ; Ausgabe-Prozedur für Zeichen

  move.l  4,a6                 ; Exec.RawDoFmt aufrufen
  jsr     _LVORawDoFmt(a6)

  add.l   HIGHS,sp               ; Stack korrigieren
  add.l   OFFS,sp
  movem.l (sp)+,a4/a5            ; a4/a5 holen
  move.l  (sp),a0
  lea     20(sp),sp
  add.l   OFFS,sp
  jmp     (a0)

; Diese Prozedur wird von RawDoFmt Aufgerufen.
; Das Zeichen das ausgegeben werden soll,ist in d0
PutChProc:
  movem.l HELP/HELP2,-(sp)       ; HELP/HELP2 retten
  lea     Backslash(pc),HELP2    ; War das letzte Zeichen ein Backslash ?
  tst.b   (HELP2)
  beq.s   1$                     ; Wenn nein : Sprung

  ; Backslash-Auswertung
  clr.b   (HELP2)                ; Backslash-Flag := FALSE
  lea     ConvTable(pc),HELP     ; Aus der Konvertierungs-Tabelle
  moveq   #7,d1                  ; das Ersatzzeichen suchen
4$:
  cmp.b   (HELP)+,d0
  beq.s    5$
  addq.l  #1,HELP
  dbra    d1,4$
  bra.s   2$
5$:
  move.b  (HELP),d0              ; Zeichen in Puffer screiben
  bra.s   2$

  ; Normale-Auswertung
1$:
  cmp.b   #bs,d0                 ; Ist das Zeichen ein Backslash ?
  bne.s   2$
  move.b  #1,(HELP2)             ; Ja: Backslash-Flag setzen
  bra.s   3$

  ; Zeichen schreiben
2$:
  cmp.l   BufEnd(pc),BUFFER      ; Ist Ausgabe-Puffer voll ?
  bgt.s   3$
  move.b  d0,(BUFFER)+           ; Nein: Zeichen in Puffer schreiben
  ; Ende
3$:
  movem.l (sp)+,HELP/HELP2       ; HELP/HELP2 holen
  rts

ConvTable:                       ; Konvertierungs-Tabelle
  dc.b    '0',0
  dc.b    'b',8
  dc.b    't',9
  dc.b    'n',10
  dc.b    'r',13
  dc.b    'f',12
  dc.b     bs,bs
  dc.b    '[',155

Backslash:                       ; Backslash-Flag
  ds.b    1

  CNOP    0,2

BufEnd:                          ; Puffer-Endadresse
  ds.l    1

;--------------------------------------------------------------------

Printf0:
  moveq   #0,d7
  bra.s   Printf

Printf1:
  moveq   #1,d7
  bra.s   Printf

Printf2:
  moveq   #2,d7
  bra.s   Printf

Printf3:
  moveq   #3,d7
  bra.s   Printf

Printf4:
  moveq   #4,d7
  bra.s   Printf

Printf5:
  moveq   #5,d7
  bra.s   Printf

Printf6:
  moveq   #6,d7
  ;bra.s   Printf

Printf:                          ;d7: Anzahl Parameter
  move.l  d7,d0                  ;d0: Schleifen-Zähler
  addq.l  #1,d0

  move.l  d7,d1                  ;d1: Kopier-Offset
  lsl.l   #2,d1
  move.l  d1,d2
  add.l   #32,d1

  addq.l  #8,d2                  ;Offset zur Stack-Korrektur berechnen
  move.l  d2,-(sp)               ;und auf Stack retten

  move.l  A4,-(sp)               ;Alten Data-Pointer zeigen
  move.l  dataPtr(pc),A4         ;Eigener Data-Pointer

  moveq   #bufSize-1,d3          ;Parameter für SPrintf(buffer,,,,) und
  move.l  d3,-(sp)               ;writeProc(buffer) auf den Stack legen
  pea     -126(a4)

  move.l  d3,-(sp)
  pea     -126(a4)

loop
  move.l  0(sp,d1.l),-(sp)
  dbra    d0,loop

  bsr     SPrintf                ;Sprintf aufrufen

  move.l  -6(a4),a3              ;writeProc aufrufen
  jsr     (a3)
  move.l  (sp)+,a4               ;alten Daten-zeiger holen
  move.l  (sp)+,d0               ;Offset zur Stack-Korrektur
  move.l  (sp)+,a0               ;Rücksprungadresse
  add.l   d0,sp                  ;Stack Korrigieren
  jmp     (a0)                   ;Rücksprung

ErrorMsg:
  dc.b    'PRINTF: NO OUTPUT',0

  CNOP    0,2

WriteToOutput:                   ;Default-Ausgabeprozedur
  move.l  a4,-(sp)
  move.l  dataPtr(pc),a4
  link    a5,#0

  tst.l   writeHandle(a4)        ;Assert(writeHandle # NIL,ADR("PRINTF : .. "));
  sne     D6
  move.b  D6,-(sp)
  pea     ErrorMsg(pc)
  move.l  ArtsBs_(pc),a6
  jsr     Assert(a6)

  move.l  12(a5),a1              ;ADR(String)
  move.l  16(a5),d1              ;HIGH(String)
  move.l  a1,a0                  ;Stringlänge ermitteln
count_loop:                      ;         .
  tst.b   (a1)+                  ;         .
  dbeq    d1,count_loop          ;         .
  bne.s   end_of_string          ;         .
  subq.l  #1,a1                  ;         .
end_of_string:                   ;         .
  suba.l  a0,a1                  ;         .

  move.l  writeHandle(a4),d1     ;Write(writeHandle,ADR(String),Length(String));
  move.l  12(a5),d2
  move.l  a1,d3
  move.l  dos_lBs(pc),a6
  jsr     _LVOWrite(a6)

  unlk    a5
  move.l  (sp)+,a4
  move.l  (sp)+,a0
  addq.l  #8,sp
  jmp     (a0)

Main:
  move.l  a4,-(sp)
  move.l  dataPtr(pc),a4
  bset    #0,-2(a4)
  bne.s   noInit
  move.l  ArtsBs_(pc),a6         ;Arts.Startup
  jsr     -6(a6)
  lea     WriteToOutput(pc),a3   ;writeHandle := Output();
  move.l  a3,-6(a4)
  move.l  dos_lBs(pc),a6
  jsr     _LVOOutput(a6)
  move.l  D0,writeHandle(a4)
noInit:
  move.l  (sp)+,a4
  rts

ENDE:
  END
