***************************************************************************** ** ** ** S T A R T U P - Universeller Startup-Code für Workbench und CLI ** ** ** ** by Christian A. Weber, Zürich/Switzwerland ** ** ** ***************************************************************************** ** ** ** Universeller Startup-Code für CLI und WorkBench, öffnet die dos- ** ** library (DOSBase), schreibt Adresse unseres Tasks nach 'Process- ** ** Base'. Falls wir von der WorkBench gestartet wurden, wird die ** ** WorkBenchStartupMessage abgeholt und auf unser Directory ein Cur- ** ** rentDir() gemacht. Alle Register bleiben erhalten (BCPL...), ** ** z.B. steht bei Start vom CLI in D0 die Länge der Argument-Zeile, ** ** und in A0 steht ein Zeiger darauf. Bei Start von der WorkBench ** ** steht in D0 eine 0 und in A0 ein Zeiger auf die WBStartupMessage. ** ** ** ** Das Programm kann durch RTS beendet werden (ReturnCode D0) oder ** ** mittels der Routinen '@Exit' oder '@exit' (auch ReturnCode D0). ** ** ** ***************************************************************************** ** ** ** Es existieren zur Zeit 3 verschiedene Versionen: ** ** ** ** Startup.o - Standard Startup-Code ** ** ** ** DetachStartup.o - Hängt sich vom CLI ab ** ** Die Stacksize des Prozesses kann beim Linken ** ** mit DEFINE _STACKSIZE=12345 angegeben werden. ** ** ** ** TinyStartup.o - Öffnet keine Windows, kein StdIn/Out/Err ** ** ** ***************************************************************************** ** ** ** Modification History ** ** -------------------- ** ** ** ** 07-Sep-87 V1.0 Project started ** ** ** ** 01-Feb-88 V1.5 Versteht nun Strings in Gänsefüßchen (tnx JMH) ** ** 17-Jun-88 V1.6 'dos.library' moved from data to code segment ** ** 12-Jul-88 V2.0 _CliParse extracted to separate file, no stack ** ** 16-Nov-88 V2.1 Gründlich aufgeräumt, ist jetzt nur in chw.lib ** ** 21-Nov-88 V2.2 Default-StdWindowName added ** ** 02-Jan-88 V2.3 Default-StdWindowName wieder rausgeworfen ** ** 06-Feb-89 V2.4 An neues Library-Konzept angepasst (Labelnamen) ** ** 10-Feb-89 V2.5 Läuft nun auch mit Lattice asm und C ** ** 12-Feb-89 V2.6 Läuft nun auch mit SmallCode Aztec C ** ** 18-Mar-89 V3.0 Detach added (tnx CHH!) ** ** 02-Apr-89 V3.1 Lattice exit() has now registerized parameters ** ** 25-Jun-89 V3.2 An Genim2 angepasst und gekürzt, Detach besser ** ** 16-Jul-89 V3.3 Prozessname bei Detach stimmt wieder ** ** 12-Aug-89 V3.4 stderr implementiert ** ** 25-Sep-89 V3.5 ARP version implementiert ** ** 03-Nov-89 V3.6 Tiny-Version (ohne stdin/out/err/window) impl. ** ** 12-Jan-90 V3.7 ARP-Version von Exit rettet D2 (für result2) ** ** 15-Jan-90 V3.8 ARP-Version in separaten Source verlegt ** ** 21-Jul-90 V3.9 NewOS-Flag added (nicht im TinyStartup) ** ** 22-Jul-90 V4.0 Öffnet GfxBase und IntuitionBase ** ** 05-May-91 V4.1 NewOS erst ab V37 (früher V36) ** ** 30-May-91 V4.2 _STACKSIZE von ARPStartup auch hier eingebaut ** ** 21-Jul-91 V4.3 BSS-Bereich wird gelöscht -> kürzere Programme ** ** 02-Apr-92 V4.4 Genam statt asm -> Detach läuft wieder ** ** ** ***************************************************************************** IDNT Startup SECTION text,CODE INCLUDE "exec/types.i" INCLUDE "exec/macros.i" INCLUDE "exec/execbase.i" INCLUDE "dos/dosextens.i" INCLUDE "workbench/startup.i" ***************************************************************************** ** Referenzen XREF @Main ; Hauptprogramm, das aufgerufen wird XREF _LinkerDB ; Start des Datenbereichs XREF __BSSBAS ; Start des __MERGED BSS-Bereichs XREF __BSSLEN ; Länge in LONGS des __MERGED BSS-Bereichs IFD DETACH XREF _STACKSIZE ; Grösse des Stapels ENDC IFND TINY XREF _StdWindowName ; Workbench-Window-Name, z.B. 'NIL:' ENDC ***************************************************************************** ** Definitionen XDEF _geta4 ; A4 holen für Small Data XDEF @exit,@Exit ; Fehler-Ausgang XDEF _SysBase XDEF _DOSBase XDEF _ProcessBase ; Zeiger auf unseren Prozess IFND TINY XDEF StdErr,_StdErr ; Immer CLI-Window oder WB-Window XDEF NewOS,_NewOS ; Flag ob Kick 2.x ENDC ***************************************************************************** ** Einsprung FirstByte: bra.b _WbStartup ;; dc.w $4AFC ; ARP Magic ;; dc.l _STACKSIZE ; ARP StackSize ;; dc.l 0 ; ARP data size if resident dc.b "CHW",0 ; Für mein Ego :-) dc.b "4.4",0 ; Startup-Version DOSName: dc.b "dos.library",0 *** A4 holen, Testen ob 2. Durchgang von Detach _WbStartup: bsr _geta4 IFD DETACH tst.b FirstTime(a4) ; 1. Mal hier ? bne SecondTime ; nein ---> ENDC *** BSS-Bereich löschen lea __BSSBAS(a4),a3 ; get base of BSS move.l #__BSSLEN,d3 ; get length of BSS in longwords bra.b .ClearDBF ; and clear for length given .ClearLoop: clr.l (a3)+ .ClearDBF: dbf d3,.ClearLoop IFD DETACH st.b FirstTime(a4) ; Flag setzen (jaja erst hier :-( ) ENDC *** D0/A0/SP retten, ExecBase und ThisTask holen movem.l d0/a0/a7,InitRegs(a4) movea.l (4).W,a6 move.l a6,_SysBase(a4) movea.l ThisTask(a6),a3 ; A3 : Task/Process pointer *** DOS öffnen, Verzweigung WorkBench/CLI lea DOSName(PC),a1 JSRLIB OldOpenLibrary ; DOS-Bibliothek öffnen movea.l d0,a6 ; A6 : DOSBase move.l a6,_DOSBase(a4) IFND TINY cmpi.w #36,LIB_VERSION(a6) scc.b NewOS(a4) ; Flag setzen falls Kick 2.x ENDC move.l pr_CLI(a3),d0 ; Vom CLI aufgerufen ? beq FromWorkBench ; nein ---> ***************** ***************************************************** ** Start vom CLI *** Falls erwünscht detachen IFD DETACH lsl.l #2,d0 ; BPTR to APTR movea.l d0,a2 ; A2 : struct CLI move.l cli_Module(a2),CliSegList(a4) ; SegList retten clr.l cli_Module(a2) ; für CLI löschen move.l pr_CurrentDir(a3),d1 ; Unser CurrentDir JSRLIB DupLock ; duplizieren move.l d0,ActDir(a4) ; und merken *** Kommandozeile in unseren Buffer kopieren CopyCmdLine: movea.l InitialA0(a4),a0 ; Original-ArgLine lea CommandLine,a1 ; Unsere ArgLine move.l a1,InitialA0(a4) ; reinpatchen 1$: move.b (a0),(a1)+ ; char kopieren beq.s 2$ ; ---> fertig cmpi.b #10,(a0)+ ; Endmarkierung ? bne.b 1$ ; nein ---> Loop 2$: clr.b (a1)+ ; Endmarkierung *** Command-Name als Prozess-Name von BCPL nach CSTR konvertieren *** a1 zeigt auf freien Platz für Tasknamen GetProcName: move.l a1,d1 ; D1: Name für CreateProc() move.l cli_CommandName(a2),d0 ; PrgName holen beq.b 3$ ; kein Name ---> lsl.l #2,d0 ; BPTR to APTR movea.l d0,a0 moveq.l #0,d0 move.b (a0)+,d0 ; Länge des Strings holen bra.b 2$ ; für dbf 1$: move.b (a0)+,(a1)+ ; kopieren 2$: dbf d0,1$ clr.b (a1) ; mit NULL abschliessen 3$: *** Prozess kreieren und zurück zum CLI moveq #0,d2 move.b LN_PRI(a3),d2 ; D2: Priority move.l CliSegList(a4),d3 ; D3: SegList, ist schon BPTR ;; move.l pr_StackSize(a3),d4 ; D4: StackSize ;; lsl.l #2,d4 ; Stimmt das ?? move.l #_STACKSIZE,d4 JSRLIB CreateProc ; Neuen prozess starten moveq #0,d0 ; Zum CLI zurück EndDet: rts *** Einsprung des neuen Prozesses, hat schon _geta4 gemacht SecondTime: move.l SP,InitialSP(a4) movea.l _SysBase(a4),a6 movea.l ThisTask(a6),a3 ; Neue ProcessBase holen movea.l _DOSBase(a4),a6 move.l ActDir(a4),d1 ; Unser CurrentDir JSRLIB CurrentDir ; setzen bra.b Windy ; ---> ELSE IFND TINY lea StdErrName(PC),a0 move.l a0,d1 move.l #MODE_OLDFILE,d2 JSRLIB Open move.l d0,_StdErr(a4) ENDC bra.b StartMain ; ---> ENDC ***************************************************************************** ** Register A4 holen für small data _geta4: lea _LinkerDB,a4 rts ***************************************************************************** ** Start von der Werkbank FromWorkBench: movea.l _SysBase(a4),a6 lea pr_MsgPort(a3),a0 JSRLIB WaitPort lea pr_MsgPort(a3),a0 JSRLIB GetMsg move.l d0,WBenchMsg(a4) clr.l InitialD0(a4) ; D0 : Null move.l d0,InitialA0(a4) ; A0 : WBStartup-Message movea.l d0,a0 ; Workbench Startup Message movea.l sm_ArgList(a0),a0 ; erstes Argument: wir selbst! move.l wa_Lock(a0),d1 ; Lock unseres Directories movea.l _DOSBase(a4),a6 JSRLIB CurrentDir ; als Current Dir setzen Windy: IFND TINY move.l #_StdWindowName,d1 ; Zu öffnendes Dos-Fenster move.l #MODE_OLDFILE,d2 JSRLIB Open ; Window öffnen move.l d0,OurWindow(a4) ; für Exit() IFND DETACH move.l d0,_StdErr(a4) ENDC move.l d0,pr_CIS(a3) ; für Input() move.l d0,pr_COS(a3) ; für Output() lsl.l #2,d0 ; BPTR to APTR movea.l d0,a0 move.l fh_Type(a0),pr_ConsoleTask(a3) ; für Open("*",mode); ENDC **************** ***************************************************** ** Hauptprogramm starten StartMain: move.l a3,ProcessBase(a4) ; für die Aussenwelt movem.l InitRegs(a4),d0/a0 jsr @Main(PC) ; PROGRAMM AUSFÜHREN! *** Programm-Termination durch Exit(val) oder return(val) @exit: @Exit: bsr.b _geta4 IFND DETACH move.l d0,d7 ; return-code retten ENDC movea.l InitialSP(a4),SP ; Stackpointer restaurieren IFND TINY movea.l _DOSBase(a4),a6 move.l OurWindow(a4),d1 ; Fenster oder 0 beq.b 1$ JSRLIB Close ; Fenster schliessen 1$: ENDC move.l WBenchMsg(a4),d2 ; gibt's was zu beantworten? beq.b 2$ ; nein, CLI ---> movea.l _SysBase(a4),a6 JSRLIB Forbid ; sonst werden wir 'entladen' ! movea.l d2,a1 JSRLIB ReplyMsg IFND TINY bra.b QuitnDie ; ---> raus! ENDC 2$: IFND DETACH IFND TINY move.l _StdErr(a4),d1 ; StdErr schliessen if CLI movea.l _DOSBase(a4),a6 JSRLIB Close ENDC ENDC **************** ***************************************************** *** Uns selber und unseren Lock freigeben falls degetacht (CLI) IFD DETACH ;; movea.l ProcessBase(a4),a3 ;; clr.l pr_CIS(a3) ; Input handle ungültig ;; clr.l pr_COS(a3) ; Output handle ungültig movea.l _DOSBase(a4),a6 move.l ActDir(a4),d1 JSRLIB UnLock ; Altes CD freigeben move.l CliSegList(a4),d1 ; Uns selbst JMPLIB UnLoadSeg ; freigeben * NOT REACHED ENDC ***************************************************************************** ** Returncode von D7 holen und Programm beenden QuitnDie: move.l d7,d0 ; return-code rts ; ZURÜCK ZUM DOS! ***************************************************************************** IFND DETACH IFND TINY StdErrName: dc.b "*",0 ENDC ENDC ***************************************************************************** SECTION __MERGED,DATA ; Anscheinend darf die Data-Size im __MERGED-Segment nicht 0 sein, sonst ; erzeugt der Linker einen BSS-Hunk mit Länge 0 im Hunk und Länge 20 im ; Header (?!) _DOSBase: DOSBase: ds.l 1 ; wird hier geöffnet & geschlossen SECTION __MERGED,BSS _SysBase: ds.l 1 _ProcessBase: ProcessBase: ds.l 1 ; Address of this process WBenchMsg: ds.l 1 ; Startup-Message oder NULL IFND TINY _StdErr: ; MUSS vor OurWindow stehen, weil if .. StdErr: ; .. detach, StdErr=OurWindow IFND DETACH ds.l 1 ; Standard Error FileHandle ENDC OurWindow: ds.l 1 ; Zeiger auf unser Window oder NULL _NewOS: NewOS: ds.l 1 ; Flag ob Kick 2.x ENDC InitRegs: ; Die 3 geretteten Register D0/A0/SP: InitialD0: ds.l 1 InitialA0: ds.l 1 InitialSP: ds.l 1 IFD DETACH CliSegList: ds.l 1 ; Unsere Segmentliste ActDir: ds.l 1 ; Lock auf unser Current Directory FirstTime: ds.l 1 ; Flag ob 1. Mal durch ENDC IFD DETACH SECTION bss,BSS CommandLine: ds.b 2100 ; Kommandozeile und Task-Name ENDC END