*********************************
*                               *
*        Free-Space V3.1        *
*                               *
*-------------------------------*
*    SOURCE-Listing für den     *
*        A68K-Assembler         *
*                               *
*      v. Stefan Hußfeldt       *
*         Wielandstr. 8         *
*         2400 Lübeck 1         *
*********************************
;
;	Anwendung:	FreeSpace [-k] [-s] [-c] [-f] <[Gerät]|[-m]> <Bytes>
;
;			Gerät = df0:...df3:, dh1:, vd0:, usw.
;			-m = RAM-Speicher
;
;			Bytes = Anzahl der geforderten freien Bytes
;
;			-k = Bytes sind K-Bytes
;			-s = kein Schreibschutz-Test (bei [Gerät])
;
;			-c = fordert CHIP-RAM an
;			-f = fordert FAST-RAM an
;
;	RückMeldung:	ReturnCode = 0	: Gerät/Computer bietet genügend Platz
;			ReturnCode = 5	: Gerät/Computer bietet NICHT genügend Platz
;			ReturnCode = 30	: Syntax-Fehler
;
;	Beispiel:	'FreeSpace -s DF2: 8342' fordert von DF2: 8342 Bytes an.
;			'FreeSpace -k DH1: 53'   fordert von DH1: 53 K-Bytes an.
;			'FreeSpace -m -f -k 350' fordert 350K-Bytes FAST-RAM an.
;
;-------------------------------------------------------------------------------------

EXECBase        EQU 4         ;EXEC-Base

OpenLibrary     EQU -552      ;EXECLib-Offset, öffnet Library
CloseLibrary    EQU -414      ;EXECLib-Offset, schließt Library
FindTask        EQU -294      ;EXECLib-Offset, findet TaskStruktur
AvailMem        EQU -216      ;EXECLib-Offset, Speicher erfragen

IoErr           EQU -132      ;DOSLib-Offset, ermittelt Ein-/Ausgabefehler
Info            EQU -114      ;DOSLib-Offset, ermittelt Infos über Disk  
UnLock          EQU -90       ;DOSLib-Offset, löscht Lock-Struktur
Lock            EQU -84       ;DOSLib-Offset, ermittelt Lock-Struktur
Output          EQU -60       ;DOSLib-Offset, ermittelt Output-Handle
Write           EQU -48       ;DOSLib-Offset, Ausgabe

MEMF_PUBLIC     EQU $01
MEMF_CHIP       EQU $02
MEMF_FAST       EQU $04

pr_WindowPtr    EQU 184
tc_UserData     EQU 88

ACCESS_READ     EQU -2        ;Datei-, Geräte-Zugriffsmodus

Warn            EQU 5
Fail            EQU 30

SFlag           EQU 0         ;Schreibschutz-Test
KFlag           EQU 1         ;K-Byte Anforderung
MFlag           EQU 2         ;Speicher-Test

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

	move.l	a0,a5			;Übergabe-Parameter sichern

	move.l	EXECBase,a6
	lea	Dosname(pc),a1
	moveq   #0,d0
	jsr     OpenLibrary(a6)		;DOS-Library öffnen
        move.l  d0,DOSBase
	beq	NoDosLib

	move.l	d0,a6
	jsr	Output(a6)		;Output-Handle ermitteln
	move.l	d0,OutHandle		;und merken

	move.l	a5,a0			;Parameter zurückholen

DecodeParameter:
	cmp.b	#$0a,(a0)
	beq	ZeigeHilfe		;Parameter-Fehler
	cmp.b	#' ',(a0)+
	beq.s	DecodeParameter

	move.b	-(a0),d0
	cmp.b	#'-',d0
	bne.s	ParCont
	addq.l	#1,a0
	move.b	(a0)+,d0
	bset	#5,d0			;Groß -> KleinBuchstabe

	cmp.b	#'s',d0			;Schreibschutz-Test vornehmen ?
	bne.s	NextFlagI
	bset	#SFlag,Flags
	bra.s	DecodeParameter
NextFlagI:
	cmp.b	#'m',d0			;Speicher anfordern ?
	bne.s	NextFlagII
	bset	#MFlag,Flags
	bra.s	DecodeParameter
NextFlagII:
	cmp.b	#'c',d0			;soll es CHIP-RAM sein ?
	bne.s	NextFlagIII
	move.b	#MEMF_CHIP,MemTyp
	bra.s	DecodeParameter
NextFlagIII:
	cmp.b	#'f',d0			;soll es FAST-RAM sein ?
	bne.s	NextFlagIV
	move.b	#MEMF_FAST,MemTyp
	bra.s	DecodeParameter
NextFlagIV:
	cmp.b	#'k',d0			;K-Bytes anfordern ?
	bne	ZeigeHilfe		;Parameter-Fehler
	bset	#KFlag,Flags
	bra.s	DecodeParameter

ParCont:
	btst	#MFlag,Flags
	bne.s	NotDevice

	lea	Name(pc),a1
	cmp.b	#$22,(a0)
	bne.s	ParPhyDevLoop
	addq	#1,a0
ParLogDevLoop:
	move.b	(a0)+,(a1)+		;logischen GeräteNamen in Puffer kopieren
	cmp.b	#$0a,(a0)		;Paramater-Fehler
	beq	ZeigeHilfe
	cmp.b	#$22,(a0)
	bne.s	ParLogDevLoop		;GeräteName zu Ende ?
	addq	#1,a0			;Adress-Zeiger korrigieren
	beq.s	NotDevice
ParPhyDevLoop:
	move.b	(a0)+,(a1)+		;physikalischen GeräteNamen in Puffer kopieren
	cmp.b	#$0a,(a0)		;Parameter-Fehler
	beq	ZeigeHilfe
	cmp.b	#' ',(a0)		;GeräteName zu Ende ?
	bne.s	ParPhyDevLoop

NotDevice:
	lea	ParBuf(pc),a1
ParSpaceLoop:
	cmp.b	#$0a,(a0)
	beq	ZeigeHilfe		;Parameter-Fehler
	cmp.b	#' ',(a0)+
	beq.s	ParSpaceLoop

	subq.l	#1,a0
	move.b	#$0a,10(a0)		;maximal 10 Ziffern
ParLoop:
	move.b	(a0)+,d0
	cmp.b	#$0a,d0
	beq.s	ParEnde			;Parameterende
	cmp.b	#' ',d0
	beq.s	ParEnde			;Parameterende
	cmp.b	#';',d0
	beq.s	ParEnde			;Parameterende
	cmp.b	#'0',d0			;Zeichen <'0'
	blt	ZeigeHilfe		;Parameter-Fehler
	cmp.b	#'9',d0			;Zeichen >'9'
	bgt	ZeigeHilfe		;Parameter-Fehler
	move.b	d0,(a1)+		;in Puffer kopieren
	bra.s	ParLoop

ParEnde:
	lea	ParBuf(pc),a0
	;
	;DezimalZahl im ASCII-Format wird in HexadezimalZahl umgewandelt.
	;
	moveq	#0,d0
      	moveq	#0,d1
Dezloop:
	move.b	(a0)+,d1
	beq.s	Dezok			;lesen bis #$00-Byte
	sub.b	#$30,d1			;DezimalZahl ermitteln

	move.l	d0,d2			;diese Befehlsfolge ersetzt den
	asl.l	#1,d0			;		:
	asl.l	#3,d2			;		:
	add.l	d2,d0			;langsamen MULU-Befehl: mulu #10,d0

	bcs.s	Overflow		;Wert ist für LangWort zu groß geworden
	add.l	d1,d0
	bra.s	Dezloop

Overflow:
	moveq	#-$1,d0			;maximaler Wert ist #4.294.967.295
Dezok:
	move.l	d0,OrderedBytes		;und merken

	move.l	EXECBase,a6
	btst	#MFlag,Flags		;Speicher testen?
	beq.s	TestDevice		;NEIN -> springen

	move.b	MemTyp,d1
	ext.l	d1
	jsr	AvailMem(a6)		;möglichen Speicher ermitteln
	btst	#KFlag,Flags
	beq.s	NotKBytes
	asr.l	#8,d0			;bei Anforderung von K-Bytes durch 1024 teilen
	asr.l	#2,d0			;(der DIVU-Befehl ist langsamer)
NotKBytes:
	cmp.l	OrderedBytes(pc),d0	;hier fällt die Entscheidung
	bcs.s	SetWarnMem		;zuwenig Platz -> Warnung ausgeben
	move.w	#0,-(sp)		;alles OK, ReturnCode=0
	bsr	TextAusgabeMem
	lea	OKTextCont(pc),a0
	bra	WegHier	

SetWarnMem:
	move.w	#Warn,-(sp)		;zuwenig Platz, ReturnCode=5 (Warn)
	bsr	TextAusgabeMem
	lea	DVTextCont(pc),a0
	bra	WegHier

TestDevice:
	sub.l	a1,a1			;eigener Task
	jsr     FindTask(a6)		;Zeiger auf Taskstruktur finden
	move.l  d0,a0
	move.l	a0,TaskPointer
	move.l	pr_WindowPtr(a0),tc_UserData(a0) ;WindowPtr merken
	move.l	#-$1,pr_WindowPtr(a0)	;keine Requester mehr möglich

	move.l  DOSBase(pc),a6
        move.l  #Name,d1		;Zeiger auf GeräteName
        move.l  #ACCESS_READ,d2		;Zugriffsmodus: Lesen
	jsr	Lock(a6)		;LockStruktur für das Gerät ermitteln

	move.l	TaskPointer(pc),a0
	move.l	tc_UserData(a0),pr_WindowPtr(a0) ;Requester wieder möglich machen
	clr.l	tc_UserData(a0)

	move.l  d0,LockStructure
	beq.s	NoLock			;Keine Lockstruktur -> Fehler

	move.l	d0,d1			;Zeiger auf LockStruktur nach D1
	move.l	#Buffer,d2		;Zeiger auf Puffer für die Daten
	jsr	Info(a6)		;Info-Daten über das Gerät holen
	tst.l	d0
	beq.s	LockOut			;Keine Daten ?? -> LockOut

	btst	#SFlag,Flags
	bne.s	NoSTest
	btst	#1,DiskState+3		;Schreibschutz-Test
	beq	WriteProtected
NoSTest:
	move.l	NumBlocks(pc),d0	;Gesamt-BlockZahl
	sub.l	NumBlocksUsed(pc),d0	;Anzahl freie Blöcke
	mulu	BytesPerBlock+2(pc),d0	;multipliziert mit Bytes/Block (LSW)
	btst	#KFlag,Flags
	beq.s	NotKB
	asr.l	#8,d0			;bei Anforderung von K-Bytes durch 1024 teilen
	asr.l	#2,d0			;(der DIVU-Befehl ist langsamer)
NotKB:
	cmp.l	OrderedBytes(pc),d0	;hier fällt die Entscheidung
	bcs.s	SetWarn			;zuwenig Platz -> Warnung ausgeben
	move.w	#0,-(sp)		;alles OK, ReturnCode=0
	bsr.s	TextAusgabe
	lea	OKTextCont(pc),a0
	bsr	PrintString
	
LockOut:
	move.l	DOSBase(pc),a6
	move.l	LockStructure(pc),d1	;Gerät wieder freigeben
	jsr	UnLock(a6)

ZumEnde:
	move.l	EXECBase,a6
	move.l  DOSBase(pc),a1
	jsr     CloseLibrary(a6)	;DOS-Library schließen

	move.w	(sp)+,d0		;CLI-ReturnCode laden
NoDosLib:
	rts				;Bye, Bye...

ZeigeHilfe:
	move.w	#Fail,-(sp)		;Syntax-Fehler, ReturnCode=30 (Fail)
	lea	Hilfe(pc),a0
	bra.s	WegHier

NoLock:
	move.w	#Fail,-(sp)		;DOS-Fehler, ReturnCode=30 (Fail)
	jsr	IoErr(a6)
	cmp.b	#$e2,d0			;Keine Diskette im Laufwerk
	bne.s	NoDevice
	lea	KeineDisk(pc),a0
	bra.s	WegHier
NoDevice:
	cmp.b	#$da,d0			;Logisches Gerät nicht auffindbar
	bne.s	NotDosDisk
	bsr.s	TextAusgabe
	lea	NichtDa(pc),a0
	bra.s	WegHier
NotDosDisk:
	cmp.b	#$e1,d0			;Diskette nicht im DOS-Format
	bne.s	UnKnown
	lea	KeineDosDisk(pc),a0
	bra.s	WegHier
UnKnown:
	lea	Fatal(pc),a0		;anderer Fehler
WegHier:
	bsr.s	PrintString
	bra.s	ZumEnde

SetWarn:
	move.w	#Warn,-(sp)		;zuwenig DiskPlatz, ReturnCode=5 (Warn)
	bsr.s	TextAusgabe
	lea	DVTextCont(pc),a0
Tschau:	bsr.s	PrintString
	bra.s	LockOut

WriteProtected:
	move.w	#Fail,-(sp)		;Disk schreibgeschützt, ReturnCode=30 (Fail)
	bsr.s	TextAusgabe
	lea	WPTextCont(pc),a0
	bra.s	Tschau

TextAusgabe:
	lea	Text(pc),a0
	bsr.s	PrintString
	lea	Name(pc),a0
	bra.s	PrintString
TextAusgabeMem:
	lea	MemText(pc),a0

PrintString:
	;
	;TextZeiger in A0
	;Ausgabe erfolgt bis 0-Byte
	;
	;Register: D1,D2,D3,A0,A6
	;
	moveq	#0,d3			;Länge=0
	move.l	a0,d2			;Adresse nach D2
PLoop:	tst.b	(a0)+			;0-Byte erreicht ?
	beq.s	PrintCont		;JA, Länge bekannt in D3
	addq.w	#1,d3			;sonst Länge+1
	bra.s	PLoop			;weitertesten	

PrintCont:
	;
	;TextZeiger in D2
	;Länge in D3
	;	
	move.l	DOSBase(pc),a6
	move.l	OutHandle(pc),d1
	jsr	Write(a6)		;Text ausgeben
	rts

		cnop	0,4		;notwendig !!

DOSBase:        dc.l    0
OutHandle:	dc.l	0
LockStructure:	dc.l	0
OrderedBytes:	dc.l	0
;-------------------------------------------------------------------------------------
;
;	Struktur der mit 'Info' ermittelten Daten:
;	==========================================
;
;	Offset  | Bedeutung
;	--------|--------------------------------------------------
;	#00	= Number of SoftErrors (hier Buffer)
;	#04	= Unit-Number
;	#08	= Disk-State
;	#12	= Number of Blocks
;	#16	= Number of Used Blocks
;	#20	= Bytes per Block (OldFileSystem: 488, FASTFS: 512)
;	#24	= Disk-Type
;	#28	= Volume-Node
;	#32	= InUse
;
;-------------------------------------------------------------------------------------
Buffer:		dc.l	0
		dc.l	0
DiskState:	dc.l	0
NumBlocks:	dc.l	0
NumBlocksUsed:	dc.l	0
BytesPerBlock:	dc.l	0
		dc.l	0
		dc.l	0
TaskPointer:	dc.l	0

Flags:		dc.b	0
MemTyp:		dc.b	MEMF_PUBLIC
		even
Dosname:        dc.b    'dos.library',0
                even
Hilfe:
	dc.b	$0a,$9b,'1;31;40m  FreeSpace'
	dc.b	$9b,'0;31;40m - von Stefan Hußfeldt - © März 1990'
	dc.b	$0a,$0a,'  ',$9b,'4;33;40mAnwendung:'
	dc.b	$0a,$0a,$9b,'0;31;40m'
	dc.b	'  FreeSpace [-k] [-s] [-c] [-f] <[Gerät]|[-m]> <Bytes>',$0a,$0a
	dc.b	'      Gerät = df0:...df3:, dh1:, vd0: usw.',$0a
	dc.b	'      -m = RAM-Speicher',$0a
	dc.b	'      Bytes = Anzahl der geforderten freien Bytes',$0a
	dc.b	'      -k = Bytes sind K-Bytes',$0a
	dc.b	'      -s = kein Schreibschutz-Test (bei Gerät)',$0a
	dc.b	'      -c = fordert CHIP-RAM an (bei -m)',$0a
	dc.b	'      -f = fordert FAST-RAM an (bei -m)',$0a,$0a,$00
	even
Text:		dc.b	$0a,'Das Gerät ',$00
		even
MemText:	dc.b	$0a,'Der Computer',$00
		even
OKTextCont:	dc.b	' bietet genügend Platz !!',$0a,$0a,$00
		even
WPTextCont:	dc.b	' ist schreibgeschützt !!',$0a,$0a,$00
		even
DVTextCont:	dc.b	' bietet NICHT genügend Platz !!',$0a,$0a,$00
		even
NichtDa:	dc.b	' ist nicht vorhanden !!',$0a,$0a,$00
		even
KeineDisk:	dc.b	$0a,'Keine Diskette im Laufwerk !!',$0a,$0a,$00
		even
KeineDosDisk:	dc.b	$0a,'Keine DOS-Disk im Laufwerk !!',$0a,$0a,$00
		even
Fatal:		dc.b	$0a,'Ein unbekannter Fehler ist aufgetreten !!',$0a,$0a,$00
		even
Name:		dcb.b	40,$0	;40 Bytes reservieren (mit #$00 füllen)
		even
ParBuf:		dcb.b	11,$0	;11 Bytes           dito.
		end
