PUBLIC	ALLOC, $Buffer1, $Buffer2, $Buffer3, $Buffer4, $Buffer5, $Buffer6
PUBLIC	$Buffer7, $Buffer8, $Buffernumber, $StackInit, $WorkSpaceSegment
PUBLIC	$WorkSpaceEnd 

EXTRN	.Msg:NEAR, LastLabel:Near, $MsgAdd:Word, CBuffer1:Word
EXTRN	ActiveWindow:Byte, Initwindows:NEAR
;---------------------------------------------------------------------------
	Page ,132
NAME	FALLOC

TITLE Buffer Allocator

; MEMORY MAP:
;
; 0000 - xxxx:	Internal ( RAMDISK/MS-DOS/INTERRUPTS etc )
; xxxx - yyyy:	MAX.COM
; yyyy - zzzz:	Help Area / StackSpace
; bbb1 - bbb2:	Buffer 1 ( 64K )
; ....   ....:	Buffer 2...8
; bbb9 - xxxx:	WorkSpace ( for yankback, minimum size: 8K )
; xxxx - FFFF:	MS-DOS/Screen, etc/



	Include FDef.Def


div16	MACRO	Register
	shr	Register, 1
	shr	Register, 1
	shr	Register, 1
	shr	register, 1
ENDM

mul16	MACRO	Register
	shl	Register, 1
	shl	Register, 1
	shl	Register, 1
	shl	Register, 1

ENDM
;---------------------------------------------------------------------------
PROGRAM SEGMENT Para    PUBLIC  'Code'
	ASSUME  CS:Program, DS:Program, ES:Program, SS:Program

$BufferNumber	dw	0
$Buffer1	dw	?
$Buffer2	dw	?
$Buffer3	dw	?
$Buffer4	dw	?
$Buffer5	dw	?
$Buffer6	dw	?
$Buffer7	dw	?
$Buffer8	dw	?

$WorkspaceSegment	dw	?
$WorkspaceEnd	dw	?
$StackInit	dw	?

;---------------------------------------------------------------------------
;...........................................................................
; ALLOC:
;	IN:	LastLabel: last Symbol in command file
;		CS:[0002]: Start of MS-DOS
;
;	OUT:	SP:		directly after program and HelpSpace
;		CS:Buffer*:	after Stackspace
;		CS:WorkSpace*:	after Buffers

Alloc   PROC    Near

; 1) Initialize the stack:

	mov	CX, Offset LastLabel
	add	CX, HelpSpace+StackSpace

	pop	AX			; remember the returnaddress
	mov	SP, CX
	mov	CS:$Stackinit, CX
	push    AX			; restore the returnaddress

	div16	CX

	inc	CX			; mod 16 + 1
	mov	AX, CS
	add	CX, AX			; this is where freemem starts

	mov	DX, CS:[0002]		; this is the end
	dec	DX			; DX is end, CX is start of free
					; while CX < (DX)
	mov	BX, Offset $Buffer1

AllocNext:
	cmp	CX, DX
	jae	AllocEnd

	mov	CS:[BX], CX
	add	BX, 2
	add	CX, 1001h
	inc	CS:$Buffernumber
	jmp	Allocnext

AllocEnd:
	sub	CX, 1000h
	sub	DX, CX				; this is the amount of space
	cmp	DX, MinWorkSpace
	jae	SmallWorkBuffer

	sub	CS:$Buffernumber, 2		; we actually reassign two
	sub	BX, 4				; buffers ( one and a half )
	mov	AX, CS:[BX]
	mov	CS:$WorkSpaceSegment, AX
	mov	CS:$WorkSpaceEnd, 0FFF0h
	jmp	ReportSpace

SmallWorkBuffer:

	dec	CS:$Buffernumber		; reassign last buffer as
	sub	BX, 2				; our workspace
	mov	AX, CS:[BX]
	mov	CS:$WorkSpaceSegment, AX

	mov	CX, CS:[0002]
	sub	CX, AX
	dec	CX
	mul16	CX
	mov	CS:$WorkSpaceEnd, CX

	call	InitBuffers

	call	InitWindows

	jmp	ReportSpace

ALLOC   ENDP
;---------------------------------------------------------------------------
InitBuffers	PROC	NEAR
	mov	CX, CS:$Buffernumber
	mov	BX, CX
	add	BX, BX
	add	BX, Offset $Buffer1

IB1:	mov	DS, CS:[BX]
	sub	BX, 2
	mov	DS:BCB.FCursor, 100h
	mov	DS:BCB.FEnd, 100h
	mov	Byte Ptr DS:[100h], EOF
	mov	DS:BCB.AuxScrStart, 100h
	mov	DS:BCB.AuxCursor, 100h
	mov	DS:BCB.ScrStart, 100h
	mov	DS:BCB.FCurCol, 1
	mov	DS:BCB.Mark, 100h
	mov	DS:BCB.ScrCursor, 0
	mov	DS:BCB.Dirty, FALSE
	mov	DS:BCB.EDMode, 0
	mov	Word Ptr DS:BCB.File, 'O'*256+'F'
	mov	WORD PTR DS:BCB.File+2, '.'*256+'O'
	mov	WORD PTR DS:BCB.File+4, 'A'*256+'B'
	mov	Word PTR DS:BCB.File+6, 'R'
	mov	DS:BCB.UnUsed, TRUE

	loop	IB1
	ret
InitBuffers	ENDP
;---------------------------------------------------------------------------
FatalMsg	db	'****> NOT ENOUGH SPACE TO OPEN BUFFER <****$'
StartMsg	db	'['
BuffernumberMsg	db	' Buffers,'
WorkSpaceMsg	db	'K Workspace]'

ReportSpace	PROC	NEAR

	mov	SI, Offset StartMsg
	mov	CX, 1
	call	.MSG
	sub	CS:$MsgAdd, 6
	mov	AL, Byte Ptr CS:$BufferNumber
	call	.Msg8

	mov	SI, Offset BuffernumberMsg
	mov	CX, 8
	call	.Msg

	mov	AX, CS:$WorkSpaceEnd
	mov	AL, AH
	shr	AL, 1
	shr	AL, 1
	call	.Msg8

	mov	SI, Offset WorkSpaceMsg
	mov	CX, 12
	call	.Msg

	cmp	CS:$BufferNumber, 0
	je	NoSpace
	ret

NoSpace:mov	AX, CS
	mov	DS, AX
	mov	DX, Offset FatalMsg
	mov	AH, 9
	int	21h
	int	20h

ReportSpace	ENDP
;--------------------------------------------------------------------------
; .Msg8:
;	IN:	AL:	8bit number
;	OUT:	Messageline=****
;
Msg8	db	'00'

.Msg8	PROC	NEAR

	mov	SI, Offset Msg8
        xor     AH, AH
                                        ; number 0..99

					; now the number is in the range 0..99
					; now we can use the AAM instruction !
	aam				; divide by 100-> DIV in AH, MOD in AL
	add     AH, '0'
	mov	CS:[SI], AH
	add     AL, '0'
	mov	CS:[SI+1], AL

	mov	CX, 2
	cmp	Byte Ptr CS:[SI], '0'
	jne	NoSuppress
	inc	SI
	dec	CX
NoSuppress:
	call	.Msg

	sub	CS:$MsgAdd, 6
	ret
.Msg8	ENDP
;---------------------------------------------------------------------------
WFormat	PROC	NEAR

	cmp	AL, 9
	ja	Letter
Number:	add	AL, '0'
	ret
Letter:	add	AL, 'A'-10
	ret

WFormat	ENDP
;---------------------------------------------------------------------------
; .Msg16:
;	IN:	AX:	16bit number
;	OUT:	Messageline=****
;
Msg16	db	'0000'

.Msg16	PROC	NEAR

	mov	DI, Offset Msg16
	mov	BX, AX

	mov	AL, BH
	and	AL, 11110000b		; digit 1
	div16	AL
	call	WFormat

	mov	CS:[DI], AL
	inc	DI

	mov	AL, BH			; digit 2
	and	AL, 00001111b
	call	WFormat
	mov	CS:[DI], AL
	inc	DI

	mov	AL, BL			; digit 3
	and	AL, 11110000b
	div16	AL
	call	WFormat
	mov	CS:[DI], AL
	inc	DI

	mov	AL, BL			; digit 4
	and	AL, 00001111b
	call	WFormat
	mov	CS:[DI], AL

	mov	SI, Offset Msg16
	mov	CX, 4
	call	.Msg

	sub	CS:$MsgAdd, 4
	ret


.Msg16	ENDP

PROGRAM	ENDS
END
