
;******************************************************************************
; Startup.asm                               Copyright 1990 by Dietmar Heidrich
;
; Startup-Modul für alle Assembler-Programme.  Dieses Modul ist reentrant und
; arbeitet unter dem CLI und der Workbench.
; Der Code ist dem im Addison-Wesley "ROM Kernel Reference Manual" ähnlich, nur
; wurden alle Fehler entfernt, und das Parsen der CLI-Parameter berücksichtigt
; nun die Konventionen des DOS, d.h. der String "a**b" ergibt den Namen "a*b".
;
; Das Assembler-Programm muß beim Label "_main" beginnen, welches durch XDEF
; global deklariert wird, und kann durch den Aufruf von "_exit" mit dem Fehler-
; code in D0 terminieren.
; Beim Aufruf von der Workbench aus wird _main ein Zeiger auf die Workbench-
; Message in A0 übergeben, und D0 enthält Null.
; Beim Aufruf vom CLI aus wird _main die Anzahl von CLI-Argumenten in D0 und
; der Zeiger auf das Feld mit den Zeigern auf die Argument-Strings in A0 über-
; geben.
; D0 und A0 werden auch auf den Stack geschoben ( 4(SP) für D0, 8(SP) für A0 ).
; Darüberhinaus können die Zeiger _DOSBase, _stdin, _stdout und _stderr benutzt
; werden.
;******************************************************************************



      CODE



      INCLUDE  "exec/types.i"
      INCLUDE  "exec/alerts.i"
      INCLUDE  "exec/tasks.i"
      INCLUDE  "libraries/dos.i"
      INCLUDE  "libraries/dosextens.i"
      INCLUDE  "workbench/startup.i"
      INCLUDE  "lvo/exec.i"
      INCLUDE  "lvo/dos.i"



      XDEF  _exit
      XDEF  _SysBase
      XDEF  _DOSBase
      XDEF  _stdin
      XDEF  _stdout
      XDEF  _stderr



      XREF  _main



BP       EQUR  A5

_SysBase EQU   4

MAXIMUM_ARGUMENTE EQU   40
MAXIMUM_ARGBUFFER EQU   256
LF                EQU   10
SPACE             EQU   ' '



CALL  MACRO
   IFEQ NARG-2
      move.l   \2,a6
   ENDC
   IFLE NARG-2
      jsr      _LVO\1(a6)
      MEXIT
   ENDC
      FAIL  CALL MACRO ERROR
      ENDM



PSTRING  MACRO
   IFEQ NARG-1
      dc.b  end\@-1-*,'\1',LF
end\@ 
      MEXIT
   ENDC
      FAIL  PSTRING MACRO ERROR
      ENDM










;******************************************************************************

Startup
      ; Wir müssen reentrant sein.
      lea      BA(PC),BP            ; Basiszeiger
      move.l   SP,HauptSP-BA(BP)    ; rette SP
      movem.l  d0/a0,Register-BA(BP)
      clr.l    _WBenchMsg-BA(BP)
      clr.l    WBenchFile-BA(BP)
      moveq    #-1,d0
      lea      _stdin-BA(BP),a0
      move.l   d0,(a0)+
      move.l   d0,(a0)+
      move.l   d0,(a0)+

      ; Hole die Adresse unserer Task.
      sub.l    a1,a1
      CALL     FindTask,_SysBase
      move.l   d0,a4                ; Zeiger auf Task-Struktur

      ; Wurden wir vom CLI gestartet ?
      tst.l    pr_CLI(a4)
      bne      CLIStartup










;******************************************************************************
; Workbench-Startup-Code.

WorkbenchStartup
      bsr.s    OeffneDOS

      ; Hole die Workbench-Message.
      lea      pr_MsgPort(a4),a0
      CALL     WaitPort             ; A6 enthält schon _SysBase
      lea      pr_MsgPort(a4),a0
      CALL     GetMsg
      move.l   d0,_WBenchMsg-BA(BP)

      ; Hole das erste Argument.
      move.l   _DOSBase-BA(BP),a6
      move.l   d0,a3                ; Workbench-Message-Zeiger
      move.l   sm_ArgList(a3),d0
      beq.s    1$

      ; Setze das aktuelle Directory.
      move.l   d0,a0
      move.l   wa_Lock(a0),d1
      CALL     CurrentDir

      ; Hole das Toolwindow-Argument.
1$    move.l   sm_ToolWindow(a3),d1
      beq.s    2$

      ; Öffne das Fenster.
      move.l   #MODE_OLDFILE,d2
      CALL     Open
      move.l   d0,WBenchFile-BA(BP) ; rette Filezeiger

      ; Setze die Input- und Output-Deskriptoren.
      lea      _stdin-BA(BP),a0
      move.l   d0,(a0)+             ; setze _stdin
      move.l   d0,(a0)+             ; setze _stdout
      move.l   d0,(a0)+             ; setze _stderr
      beq.s    2$

      ; Setze die Console-Task (damit Open ("*", mode) funktioniert).
      lsl.l    #2,d0                ; BCPL-Zeiger-Konvertierung
      move.l   d0,a0
      move.l   fh_Type(a0),pr_ConsoleTask(a4)

      ; Setze die Startwerte.
2$    move.l   a3,a0                ; Workbench-Message-Zeiger
      moveq    #0,d0                ; d.h. von der Workbench gestartet
      bra      StarteMain










;******************************************************************************
; Öffne DOS.
; Eingabe:  A6 enthält _SysBase.
; Ausgabe:  A6 enthält _SysBase.
;           D0 enthält _DOSBase.

OeffneDOS
      clr.l    _DOSBase-BA(BP)
      lea      DOSName-BA(BP),a1
      moveq    #LIBRARY_VERSION,d0
      CALL     OpenLibrary
      move.l   d0,_DOSBase-BA(BP)
      beq.s    1$
      rts

      ; Fehler: DOS ist nicht offen.
1$    move.l   #(AG_OpenLib!AO_DOSLib),d7
      lea      AlertValue-BA(BP),a5
      CALL     Alert
      moveq    #100,d0
      bra      _exit










;******************************************************************************
; CLI-Startup-Code.

CLIStartup
      bsr.s    OeffneDOS

      ; Hole den Standard-Input/Output-Handle.
      move.l   d0,a6                ; _DOSBase
      CALL     Input
      move.l   d0,_stdin-BA(BP)
      CALL     Output
      move.l   d0,_stdout-BA(BP)
      move.l   d0,_stderr-BA(BP)

      ; Finde den Kommandonamen.
      move.l   pr_CLI(a4),a0
      add.l    a0,a0                ; BCPL-Zeiger-Konvertierung
      add.l    a0,a0
      move.l   cli_CommandName(a0),a0
      add.l    a0,a0                ; BCPL-Zeiger-Konvertierung
      add.l    a0,a0

      ; Initialisiere Zähler und Zeiger.
      move.l   #MAXIMUM_ARGBUFFER-1,d7
      moveq    #MAXIMUM_ARGUMENTE-2,d6 ; Argumentzähler
      lea      Zeigerfeld,a4
      move.l   a4,a1
      lea      Stringspeicher-Zeigerfeld(a4),a3

      ; Hole den Kommandonamen.
      moveq    #0,d0
      move.b   (a0)+,d0             ; Stringlänge
      sub      d0,d7                ; Unterlauf ?
      bcs.s    errorBufferOverflow  ; ja, Fehler
      move.l   a3,(a1)+             ; Zeiger auf Kommandonamen
      bra.s    1$

2$    move.b   (a0)+,(a3)+          ; Kopiere Zeichen
1$    dbra     d0,2$                ; bis Name zu Ende

      clr.b    (a3)+                ; beende Kommandenamen
      movem.l  Register-BA(BP),d0/a0
      cmp.l    d7,d0                ; Kommandozeile zu lang ?
      bhs.s    errorBufferOverflow  ; ja

      ; Parse die Argumente.
      moveq    #SPACE,d5            ; verkürzt Code
      moveq    #'"',d3              ; verkürzt Code
      bra      NaechstesArgument



ArgSchleife
      move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; legales Zeichen (cmp #' ') ?
      bls.s    NaechstesArgument    ; nein, nächstes Zeichen

      move.l   a3,a2                ; Zeiger auf Argumentpuffer-Stelle merken
      cmp.b    d3,d4                ; ist es doppeltes Hochkomma (cmp #'"') ?
      bne.s    1$                   ; nein
      bra.s    3$                   ; ja



      ; Argument darf mit einem SPACE enden.
2$    move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; Argument beendet (cmp #' ') ?
      bls.s    ArgEnd               ; ja
1$    cmp.b    #'=',d4              ; ein '=' ist nicht erlaubt
      beq.s    errorEquateUse       ; wenn Fehler
      move.b   d4,(a3)+             ; speichere Zeichen
      dbra     d0,2$                ; Zeichen übrig ?
      bra.s    ArgEnd               ; nein



      ; Argument ist in doppelte Hochkommata eingefaßt.
4$    move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; Argument beendet (cmp #' ') ?
      blo.s    errorIllegalArgEnd   ; ja, Fehler

      ; Endet Argument mit doppeltem Hochkomma ?
      cmp.b    d3,d4                ; (cmp #'"')
      bne.s    5$                   ; nein
      subq     #1,d0                ; Zeichen übrig ?
      blt.s    ArgEnd               ; nein, alles OK
      move.b   (a0)+,d4             ; ja, nächstes Zeichen
      cmp.b    d5,d4                ; legales Zeichen (cmp #' ') ?
      bls.s    ArgEnd               ; ja, alles OK
      bra.s    errorIllegalArgEnd   ; nein, Fehler

      ; Ist es ein Stern ?
5$    cmp.b    #'*',d4
      bne.s    6$                   ; nein, speichere Zeichen
      subq     #1,d0                ; Zeichen übrig ?
      blt.s    errorIllegalArgEnd   ; nein, Fehler
      move.b   (a0)+,d4             ; hole Zeichen
      cmp.b    d5,d4                ; Argument beendet (cmp #' ') ?
      blo.s    errorIllegalArgEnd   ; ja, Fehler

6$    move.b   d4,(a3)+             ; speichere Zeichen

      ; Es MUß noch Zeichen geben, oder Fehler.
3$    dbra     d0,4$                ; Zeichen übrig ?



errorIllegalArgEnd
      lea      TextIllegalArgEnd-BA(BP),a0
      bra.s    errorOut

errorBufferOverflow
      lea      TextBufferOverflow-BA(BP),a0
      bra.s    errorOut

errorEquateUse
      lea      TextEquateUse-BA(BP),a0
      bra.s    errorOut

errorTooManyArguments
      lea      TextTooManyArguments-BA(BP),a0

errorOut
      moveq    #0,d3
      move.b   (a0)+,d3             ; Stringlänge
      move.l   a0,d2                ; Stringzeiger
      move.l   _stderr-BA(BP),d1    ; Filezeiger
      CALL     Write                ; Fehler ausgeben, A6 enthält _DOSBase
      moveq    #10,d0               ; Fehlercode
      bra.s    _exit                ; und Ende



ArgEnd 
      clr.b    (a3)+                ; Argumentende
      subq.l   #1,d6                ; noch freie Zeiger übrig ?
      ble.s    errorTooManyArguments   ; nein
      move.l   a2,(a1)+             ; merke Zeiger auf Argumentstring

NaechstesArgument
      dbra     d0,ArgSchleife       ; Zeichen übrig ?

      ; Setze die Startwerte.
      move.l   a4,a0                ; Zeiger auf Zeigerfeld
      neg      d6
      add      #MAXIMUM_ARGUMENTE-1,d6 ; Zeigeranzahl
      move.l   d6,d0                ; nach D0

StarteMain
      ; Starte das Assembler-Programm.
      move.l   a0,-(SP)             ; Startwerte auf den Stack
      move.l   d0,-(SP)
      jsr      _main

      ; danach quittiere durch _exit...










;******************************************************************************
; Die Exit-Funktion.
; Eingabe:  D0 enthält den Rückgabe-Code.
; Ausgabe:  Keine Rückkehr.

_exit 
      move.l   d0,d7                ; rette Fehlercode
      move.l   HauptSP(PC),SP       ; SP laden

      ; Schließe das Workbench-Fenster.
      move.l   _DOSBase(PC),d0
      move.l   d0,a6
      beq.s    1$                   ; wenn DOS nicht offen
      move.l   WBenchFile(PC),d1
      beq.s    2$
      CALL     Close                ; schließe das Fenster

      ; Schließe das DOS.
2$    move.l   a6,a1                ; _DOSBase
      CALL     CloseLibrary,_SysBase

      ; Workbench-Startup ?
1$    move.l   _WBenchMsg(PC),d6
      beq.s    3$
      ; Gib die Workbench-Message zurück.  Forbid, damit wir nicht UnLoadSeg
      ; erleiden, bevor wir ins DOS zurückgekehrt sind.
      CALL     Forbid
      move.l   d6,a1
      CALL     ReplyMsg

      ; Zurück ins DOS.
3$    move.l   d7,d0
      rts










;******************************************************************************
; Variablen.

      CNOP    0,4             ; für MC68020

BA          ; Basisadresse

_DOSBase    ds.l  1

_stdin      ds.l  1
_stdout     ds.l  1
_stderr     ds.l  1

HauptSP     ds.l  1
_WBenchMsg  ds.l  1
WBenchFile  ds.l  1

Register    ds.l  2

AlertValue  dc.l  -1

DOSName  DOSNAME

TextIllegalArgEnd    PSTRING <Illegal argument>
TextBufferOverflow   PSTRING <Argument buffer overflow>
TextEquateUse        PSTRING <Illegally used ''=''>
TextTooManyArguments PSTRING <Too many arguments>





      BSS

      CNOP  0,4

Zeigerfeld     ds.l  MAXIMUM_ARGUMENTE
Stringspeicher ds.b  MAXIMUM_ARGBUFFER










; Ende des Startup-Moduls

        END

