xVersion	equ	'2'
yVersion	equ	'0'
;**** MAKEST Version x.y ****
;
;Copyright (c) Peter C. Cole   March, 1985   Duncanville, TX
;All commercial rights reserved.
;Released for free distribution only. Not to be sold.


;**** Version Changes ****
;
;1.0  - Released March, 1985
;
;1.1  - Added "user selectable drive" and 
;	"display existing EXECST.COM command line".
;
;1.2  -	Added "exit MAKEST only on command".
;	DO NOT USE THIS VERSION.
;
;1.3  - Corrected problem of not sending proper end flag for 
;	Bdos function 47.
;
;1.4  - Corrected problem that MAKEST sometimes recognizes a one sector
;	EXECST that was not made by MAKEST.
;
;1.5  - Corrected the "chain flag" of Bdos Function 47 (Chain to 
;	Program). It was incorrectly set to 0FFh. Now set to 0h.
;	Made "Program Data Assembly Area" more straightforward.
;
;2.0  - Added on board editor and file name change capability.
;

PAGE
;**** Assembly Definations ****
NL:	equ	0A0Dh	;new line
CPage:	equ	5A1Bh	;clear page
MsgEnd:	equ	0	;message end flag
Bdos:	equ	5	;Bdos address
Stack1:	equ	4000h	;Location of MAKEST and FileName stack
Temp:	equ	Stack1+2 ;Location to store temp string for editing
Existing: equ	4800h	;Location to store existing FileName program

	org	100h
;**** Start Program ****

;Set stack
	lxi	sp,Stack1

;Set output delimiter
	mvi	c,110
	mvi	d,0
	mvi	e,MsgEnd
	call	Bdos

;Set Bdos error mode to "return and display error" 
	mvi	c,45
	mvi	e,0FEh
	call	Bdos

;Set number of read/write sectors to 2
	mvi	c,44
	mvi	e,2
	call	Bdos

;Now continue with program
	jmp	BeginMsg




;**** Exit Program ****
Exit:	jmp	0

PAGE
;**** Begin Message ****
BeginMsg: mvi	c,9
	lxi	d,BM2
	call	Bdos
	jmp	BM10

ŠBM2:	dw	CPage
	db	'****************************** MAKEST Version '
	db	xVersion,'.',yVersion,' ******************************'
	db	'Copyright (c) 1985 by Peter C. Cole'
	dw	NL
	db	'Duncanville, Texas.'
	dw	NL
	db	'All commercial rights reserved.'
	dw	NL
	db	'Released for free distribution only. Not to be sold.'
	dw	NL
	db	'****************************************'
	db	'****************************************'
	dw	NL
	db	'MAKEST will create or edit a "Command File" '	;44
	db	'on the disk drive of your choice.'		;33
	dw	NL
	db	'A "Command File" is a file that when run '	;41
	db	'will send a command string to CP/M as '	;38
	dw	NL
	db	'if you had typed it in after the '		;33
	db	'system prompt. Normal use of MAKEST is to'	;41
	dw	NL
	db	'create an EXECST file which is the first '	;41
	db	'file CP/M Plus looks for when it first'	;38
	dw	NL
	db	'boots up. Use EXECST to '			;24
	db 	'autoload a favorite program on boot up.'	;39
	dw	NL
	db	'MAKEST will only run on the Osborne '		;36
	db	'Executive. '					;11
	dw	NL,NL
	db	MsgEnd

PAGE
;**** Main Menu ****
Begin:	call	HomeIt
BM10:	mvi	c,9
	lxi	d,BM11
	call	Bdos
	jmp	BM12

BM11:	db	'Please select:'
	dw	NL
	db	'  A,B,etc - Read this disk drive for an existing '
	db	MsgEnd

BM12:	call	FileName
	mvi	c,9
	lxi	d,BM13
	call	Bdos
	jmp	BM14

BM13:	db	' command line.'
	dw	NL
	db	'  ^C or X - Exit to CP/M.'
	dw	NL
	db	'  1 - Create a new '
	db	MsgEnd

BM14:	call	FileName
	mvi	c,9
	lxi	d,BM15
Š	call	Bdos
	jmp	BM16

BM15:	db	' command line.'
	dw	NL
	db	'  2 - Change to a different file name.'
	dw	NL
	db	'  <RETURN> - Edit the below command line (if any).'
	dw	NL
	db	'  W - Write the below command line (if any) to'
	db	' a "to be selected" disk drive:'
	dw	NL,NL
	db	MsgEnd

BM16:	mvi	c,9
	lxi	d,String
	call	Bdos

	mvi	c,9
	lxi	d,BM20
	call	Bdos
	jmp	Wait

BM20:	dw	NL
	db	MsgEnd
PAGE
;**** Subroutine FileName ****
;Displays active file name
FileName: mvi	c,9
	lxi	d,FN1
	call	Bdos
	ret

FN1:	db	'EXECST',0,0	;allow for max. of 8 characters
	db	MsgEnd

;**** Subroutine Create ****
;Creates a fresh FCB
Create:	lxi	h,FcbRun
	lxi	d,FcbNew
	mvi	b,FcbEnd-FcbNew
Create1: ldax	d
	mov	m,a
	inx	h
	inx	d
	dcr	b
	jnz	Create1
	ret

;**** Subroutine HomeIt ****
;Homes cursor to just under Header and clears to end of page.
HomeIt:	mvi	c,9
	lxi	d,Clear
	call	Bdos
	ret

Clear:	db	1Bh,3Dh	;move cursor
	db	27h,20h	;to just under header
	db	1Bh,59h	;clear from cursor to end
Š	db	MsgEnd

PAGE
;**** Wait for key ****
Wait:	mvi	c,6
	mvi	e,0FDh
	call	Bdos
	cpi	3	;test if ^C
	jz	Exit
	cpi	0Dh	;<RETURN>
	jz	ReEdit
	cpi	'1'
	jz	New
	cpi	'2'
	jz	Diff
	ani	5Fh	;convert if small to cap.
	cpi	'X'	;test if X
	jz	Exit
	cpi	'W'
	jz	Write
	cpi	'A'	;is it less than 'A'?
	jc	Wait	;jmp if yes (not A to P)
	cpi	'Q'	;is it less than 'Q'?
	jc	ExistFile ;jmp if yes
	jmp	Wait	;sorry, not A to P.


;****  Open Existing File ****

;Convert to drive code and store
ExistFile: ani	1Fh
	sta	FcbNew

;Create FcbRun 
	call	Create

;Clear screen
	call	HomeIt

PAGE
;Open Existing File
	mvi	c,15
	lxi	d,FcbRun
	call	Bdos

Š;Test if file opened
	ana	a
	jz	FileExists	;jmp if file opened with no problem
	mov	a,h
	cpi	0
	jnz	BadWait

;File not found. Give message.
	mvi	c,9
	lxi	d,NoFileMsg
	call	Bdos
	jmp	BadWait

NoFileMsg: dw	NL,NL
	db	'File not found.'
	dw	NL
	db	MsgEnd


;Test Existing file
FileExists: call TestFile
	jnz	BadWait

;Makest file - give message
	mvi	c,9
	lxi	d,MSmsg1
	call	Bdos
	jmp	MS2

MSmsg1:	dw	NL,NL
	db	'Do you want to edit this file? (Y/N) '
	db	MsgEnd

PAGE
;Wait for Answer
MS2:	mvi	c,6
	mvi	e,0FDh
	call	Bdos

	cpi	'Y'
	jz	ExistEdit
	cpi	'y'
	jz	ExistEdit
	jmp	Begin

;Edit existing command string
ExistEdit: call	HomeIt
	lxi	h,Existing+Buffer-Data
	mvi	m,126	;only allow max of 126 char
	xchg
	call	LineEdit
	cpi	0
	jz	LoadBuffer
	cpi	1
	jz	Begin
	cpi	2
	jz	BadWait
	jmp	Begin


;Load from Makest file to "Buffer"
LoadBuffer: 
	lxi	h,Buffer
	lxi	d,Existing+Buffer-Data
LB0:	ldax	d	;load max char
	mov	m,a
	inx	h
	inx	d
	ldax	d	;load char returned
	mov	m,a
	inx	h
	inx	d
LB1:	ldax	d	;load data
	mov	m,a
	inx	h
	inx	d
	ana	a	;is it end flag?
	jnz	LB1	;jmp if no
	jmp	Begin
PAGE
;**** Routine New ****

;Create a string with no data
New:	lxi	h,Temp
	mvi	m,126
	inx	h
	mvi	m,0
	inx	h
	mvi	m,0

;Edit command string
	jmp	ReEdit2


;**** Routine ReEdit ****

;Move Buffer to new location
ReEdit:	lxi	h,Temp
	lxi	d,Buffer
	ldax	d	;Load max char
	mov	m,a
	inx	h
	inx	d
	ldax	d	;load char returned
	mov	m,a
	inx	h
	inx	d
ReEdit1: ldax	d
	mov	m,a
	inx	h
	inx	d
	ana	a
	jnz	ReEdit1

;Edit command string
ReEdit2: call HomeIt
	lxi	h,Temp
	mvi	m,126
	xchg
	call	LineEdit
	cpi	0
	jz	ReEdit5
	cpi	1
	jz	Begin
	cpi	2
	jz	BadWait
	jmp	Begin

;Load new command line to Buffer
ReEdit5: lxi	h,Buffer
	lxi	d,Temp
	jmp	LB0

PAGE
;**** Subroutine LineEdit ****
;
;DE = Start address of string to edit (set by user)
; 1st byte = maximum number of characters (set by user)
; 	     Does not include end flag of 0.
; 2nd byte = total number of characters returned (set by LineEdit)
;	     Does not include end flag of 0.
; 3rd byte = zero if string has no data (set by user)
; 3rd byte = not zero if string has data (string must end with 0)
;
;Preload "WhichRow" with the row number to be used for the displayed line.
; 00h = 1st row (Top row of screen)
; 01h = 2nd row
;    etc
; 17h = 24th row (Bottom row of screen)
;
;CP/M cursor is moved to far left so LineEdit can remove it.
;LineEdit Cursor will start at far left.
;Cursor will be inverse, blinking, full intensity.
;Non-cursor characters will be black background, full intensity.
;
;Nonprintable characters will not be allowed in string.
;
;MsgEnd must be 0h.
;
;Returns with accumulator set to:
; 0 - good edit. (2nd byte equals 0 to maximum characters in string)
; 1 - edit not wanted (ESC pushed)
; 2 - problem opening line (one line message given)
;
;"String" is location of data .
;"Line" is location of video ram.
;

LineMax: db	126	;maximum number of characters allowed (max = 255)
			;1st byte can be equal to or less than LineMax
WhichRow: db	17h	;row that line editor will use
StringStart: ds	2	;start address of string to edit
StringBegin: ds	2	;First char of string
String1st: ds	2	;Address of char in string that is 1st char in line
StringCursor: ds 2	;cursor location in string
LineBegin: ds	2	;start address of line
LineCursor: ds	2	;cursor location in line



PAGE
;Store start address of string
LineEdit: xchg
	shld	StringStart

;Make CP/M cursor start location same as LineEdit location
	lda	WhichRow
	ani	24
	sta	CursorY

;Send Edit header
	mvi	c,9
	lxi	d,EditMsg
	call	Bdos
	jmp	Edit3

EditMsg: db	'You can use ! to chain several commands if needed. '
	db	'Example: DIR A:!DIR B:'
	dw	NL
	db	'Enter up to 126 characters. '
Edit1:	dw	NL,NL
	db	'Use these keys for editing:'
	dw	NL,NL
	db	'  ^A - Go to far left.'
	dw	NL
	db	'  ^F - Go to far right.'
	dw	NL
	db	'  ^G or down arrow - delete character.'
	dw	NL
	db	'  ^- or ^left arrow - delete character on left.'
	dw	NL
	db	'  Use left and right arrow keys to move cursor.'
	dw	NL
	db	'  Only printable characters allowed.'
	dw	NL
	db	'  Push <ESC> to exit without new edit.'
	dw	NL
	db	'  Push <RETURN> when finished.'
	db	1Bh,3Dh		;position cursor
CursorY	db	0+32
CursorX	db	0+32
	db	MsgEnd

;Create video bank start address
Edit3:	ora	a		;clear carry
	lda	WhichRow	;get row number
	lxi	h,0C000h	;preload hl for video bank address
	rar			;get LSB of WhichRow for MSB of reg l
	mov	b,a		;store LSB's for reg h
	mov	a,l		;move LSB of WhichRow into MSB of reg l
	rar
	mov	l,a
	mov	a,b		;get LSB's for reg h
	ora	h		;move MSB's of WhichRow into LSB's of reg h
	mov	h,a		;
	shld	LineBegin	;store line start address
PAGE
;Test if max desired ok
Edit5:	lhld	StringStart
	mov	c,m	;load max char's
	inx	h
	mvi	m,0	;set to 0 char returned for now
	inx	h
	lda	LineMax	;load max allowed
	cmp	c	;test if equal to or less than
	jz	Edit8	;ok (equal)
	jnc	Edit8	;ok (less than)
	
;Max desired not ok - send message
	mvi	c,9
	lxi	d,Edit6
	call	Bdos
	mvi	a,2
	ret

Edit6:	db	'Maximum characters desired is more than that allowed.'
	db	MsgEnd

;Test if any nonprintable char found
Edit8:	
	mvi	b,0	;to keep track of number of char
	lda	LineMax	;to test if max exceeded
	inr	a	;account for end flag
	mov	c,a
Edit9:	mov	a,m
	ana	a
	jz	Edit20	;jmp if end flag of 0 found
	cpi	' '
	jc	Edit11	;jmp if control char
	cpi	7Fh
	jnc	Edit11	;jmp if equal to or greater than 7Fh
	inr	b
	dcr	c
	jz	Edit16	;jmp if max exceeded
	inx	h
	jmp	Edit9

;nonprintable char found
Edit11:	mvi	c,9
	lxi	d,Edit12
	call	Bdos
	mvi	a,2
	ret

Edit12:	db	'Sorry, this string has a nonprintable character.'
	db	MsgEnd

PAGE
;number of char's exceed limit
Edit16:	mvi	c,9
	lxi	d,Edit17
	call	Bdos
	mvi	a,2
	ret

Edit17: db	'Sorry, this string is too long.'
	db	MsgEnd
	

;does string given exceed its own limit?
Edit20:	lhld	StringStart
	mov	a,m
	cmp	b
	jnc	Edit25	;jmp if ok

;string given exceeds its own limit
	mvi	c,9
	lxi	d,Edit22
	call	Bdos
	mvi	a,2
	ret

Edit22: db	'Sorry, this string exceeds its own maximum limit.'
	db	MsgEnd
	
;Load number of char's found
Edit25:	lhld	StringStart
	inx	h
	mov	m,b

;display line
	lhld	StringStart	;preload start address of string
	inx	h
	inx	h
	shld	StringBegin
	shld	String1st
	shld	StringCursor

	lhld	LineBegin	;preload start address of line
	shld	LineCursor
	shld	OldCursor

	call	Display
	jmp	Edit

PAGE
;** Subroutine Display **
OldCursor: ds	2
Bank:	ds	1

;Turn on Video Bank
Display: in	0
	sta	Bank
	ori	40h
	out	0

;Turn off old cursor
	lhld	OldCursor
	mov	a,m
	ani	01111111b ;turn off reverse video
	mov	m,a
	mov	a,h	;go to DXXX address
	adi	10h
	mov	h,a
	mov	a,m
	ani	11011111b ;turn off blink
	mov	m,a

;Load new line data until end flag
	lhld	String1st
	xchg
	lhld	LineBegin
	mvi	b,80
Display1: ldax	d
	ana	a	;test if 0 end flag
	jz	Display2 ;jmp if yes
	mov	m,a
	inx	h
	inx	d
	dcr	b
	jnz	Display1

;Finish with blanks
Display2: mvi	a,' '
Display3: mov	m,a
	inx	h
	dcr	b
	jnz	Display3

PAGE
;Turn on new cursor and store location as OldCursor
	lhld	LineCursor
	shld	OldCursor
	mov	a,m
	ori	10000000b ;turn on inverse video
	mov	m,a
	mov	a,h	;go to DXXX address
	adi	10h
	mov	h,a
	mov	a,m
	ori	00100000b ;turn on blink
	mov	m,a

;Turn off Video Bank
	lda	Bank
	out	0
	ret

PAGE
;Wait for edit key
Edit:	mvi	c,6
	mvi	e,0FDh
	call	Bdos
	cpi	1Bh	;ESC
	jz	ExitEdit
	cpi	01h	;^A (CP/M to left edge)
	jz	LeftEdge
	cpi	06h	;^F (CP/M to right edge)
	jz	RightEdge
	cpi	07h	;^G (CP/M and WS delete character)
	jz	DeleteChar
	cpi	0Ah	;^J (CP/M Arrow down)
	jz	DeleteChar
	cpi	18h	;^X (WS Arrow down)
	jz	DeleteChar
	cpi	1Fh	;^_ (WS delete character on left - also ^ arrow left) 
	jz	DeleteLeft
	cpi	7Fh	;DEL
	jz	DeleteLeft
	cpi	04h	;^D (WS arrow right)
	jz	Right
	cpi	0Ch	;^L (CP/M arrow right)
	jz	Right
	cpi	13h	;^S (WS arrow left)
	jz	Left
	cpi	08h	;^H (CP/M arrow left)
	jz	Left
	cpi	0Dh	;^M (Carriage Return)
	jz	DoneEdit
	cpi	' '
	jc	Edit	;jmp if control char
	cpi	80h
	jnc	Edit	;jmp if equal to or greater than 80h
	jmp	EnterChar

;Return from Edit with flag of abandon edit
ExitEdit: mvi	a,1
	ret

;Return from Edit with flag of good new edit
DoneEdit: mvi	a,0
	ret

PAGE
;**** Routine Right ****
;move cursor right

;can String move right?
Right:	lhld	StringCursor
	mov	a,m
	ana	a
	jz	Edit	;jmp if no

;move String right
	inx	h
	shld	StringCursor

;can Line move right?
	lhld	LineCursor
	mov	a,l
	cpi	4Fh
	jz	RightMove ;jmp if no
	cpi	0CFh
	jz	RightMove ;jmp if no

;move Line right
	inx	h
	shld	LineCursor

;display new line
RightOut: call	Display
	jmp	Edit

;move String right
RightMove: lhld	String1st
	inx	h
	shld	String1st
	jmp	RightOut

PAGE
;**** Routine Left ****
;moves cursor left

;Can String move left?
Left:	lhld	StringBegin
	xchg
	lhld	StringCursor
	mov	a,d
	cmp	h
	jnz	Left1	;jmp if yes
	mov	a,e
	cmp	l
	jnz	Left1	;jmp if yes
	jmp	Edit	;jmp if no

;Move String left
Left1	dcx	h
	shld	StringCursor

;Can Line move left?
	lhld	LineCursor
	mov	a,l
	cpi	0h
	jz	LeftMove ;jmp if no
	cpi	80h
	jz	LeftMove ;jmp if no

;move Line left
	dcx	h
	shld	LineCursor

;display new line
LeftOut: call	Display
	jmp	Edit

;move String left
LeftMove: lhld	String1st
	dcx	h
	shld	String1st
	jmp	LeftOut

PAGE
;**** Routine RightEdge ****
;Moves cursor to far right edge

;Can String move right?
RightEdge: lhld	LineCursor	;for top
	push	h
	lhld	String1st	;for de
	xchg
	lhld	StringCursor	;for hl
	mov	a,m
	cpi	0h
	jz	REout	;jmp if no

;Move StringCursor and LineCursor right
;Can LineCursor move right
RE1:	xthl
	mov	a,l
	cpi	4Fh
	jz	RE5	;jmp if no
	cpi	0CFh
	jz	RE5	;jmp if no

;move LineCursor right
	inx	h
RE2:	xthl

;move StringCursor right
	inx	h

;can String move right
	mov	a,m
	cpi	0h
	jnz	RE1	;jmp if yes

;load new values
RE3:	shld	StringCursor
	xchg
	shld	String1st
	pop	h
	shld	LineCursor

;display new line
	call	Display
	jmp	Edit

PAGE
;Move StringCursor and String1st right
;Return LineCursor
RE5:	xthl

;move StringCursor and String1st right
RE6:	inx	h
	inx	d

;can String move right
	mov	a,m
	cpi	0h
	jnz	RE6	;jmp if yes
	jmp	RE3

REout:	pop	h
	jmp	Edit

PAGE
;**** Routine LeftEdge ****
;Moves cursor to far left edge

;Can String move left?
LeftEdge: 
	lhld	StringBegin	;for bc
	mov	b,h
	mov	c,l
	lhld	StringCursor
	mov	a,b
	cmp	h
	jnz	LE0	;jmp if yes
	mov	a,c
	cmp	l
	jnz	LE0	;jmp if yes
	jmp	Edit	;jmp if no

LE0:	lhld	LineCursor	;for top
	push	h
	lhld	String1st	;for de
	xchg
	lhld	StringCursor	;for hl

;Move StringCursor and LineCursor left
;Can LineCursor move left
LE1:	xthl
	mov	a,l
	cpi	0h
	jz	LE5	;jmp if no
	cpi	80h
	jz	LE5	;jmp if no

;move LineCursor left
	dcx	h
LE2:	xthl

;move StringCursor left
	dcx	h

;can String move left
	mov	a,b
	cmp	h
	jnz	LE1	;jmp if yes
	mov	a,c
	cmp	l
	jnz	LE1	;jmp if yes

PAGE
;load new values
LE3:	shld	StringCursor
	xchg
	shld	String1st
	pop	h
	shld	LineCursor

;display new line
	call	Display
	jmp	Edit

;Move StringCursor and String1st left
;Return LineCursor
LE5:	xthl

;move StringCursor and String1st left
LE6:	dcx	h
	dcx	d

;can String move left
	mov	a,b
	cmp	h
	jnz	LE6	;jmp if yes
	mov	a,c
	cmp	l
	jnz	LE6	;jmp if yes
	jmp	LE3	;jmp if no
PAGE
;**** Routine DeleteChar ****
;Deletes character cursor is on

;Is StringCursor at end?
DeleteChar:
	lhld	StringCursor
	mov	a,m
	dcx	h
	ana	a
	jz	Edit	;jmp if yes

;Delete data at cursor
DelChar1: inx	h
	inx	h
	mov	a,m
	dcx	h
	mov	m,a
	ana	a	;is it last char
	jnz	DelChar1 ;jmp if no

;Decrement char count
	lhld	StringStart
	inx	h
	mov	a,m
	dcr	a
	mov	m,a

;Display new line
	call	Display
	jmp	Edit
PAGE
;**** Routine DeleteLeft ****
;Delete character on left of cursor

;Is StringCursor at end?
DeleteLeft:
	lhld	StringBegin
	xchg
	lhld	StringCursor
	mov	a,d
	cmp	h
	jnz	DelLeft1	;jmp if no
	mov	a,e
	cmp	l
	jnz	DelLeft1	;jmp if no
	jmp	Edit		;jmp if yes

;Is LineCursor at end?
DelLeft1:
	lhld	LineCursor
	mov	a,l
	cpi	0h
	jz	Edit	;jmp if yes
	cpi	80h
	jz	Edit	;jmp if yes

;Decrement LineCursor position
	dcx	h
	shld	LineCursor

;Decrement StringCursor position
	lhld	StringCursor
	dcx	h
	shld	StringCursor

;Delete data at left of cursor
	dcx	h
DelLeft2: inx	h
	inx	h
	mov	a,m
	dcx	h
	mov	m,a
	ana	a	;is it last char
	jnz	DelLeft2 ;jmp if no

;Decrement char count
	lhld	StringStart
	inx	h
	mov	a,m
	dcr	a
	mov	m,a

;Display new line
	call	Display
	jmp	Edit

PAGE
;**** Routine EnterChar ****
;Enter character at cursor position. 
;Cursor and all to right moves right.

;Store character
EnterChar:
	mov	c,a	;char stored in c

;Is String full?
	lhld	StringStart
	mov	a,m
	inx	h
	cmp	m
	jnz	Char1	;jmp if no

;Send bell
	mvi	c,2
	mvi	e,7h
	call	Bdos
	jmp	Edit

;Increment String count
Char1:	mov	a,m
	inr	a
	mov	m,a

;Increment StringCursor
	lhld	StringCursor
	inx	h
	shld	StringCursor
	dcx	h

;Move in new data
Char2:	mov	a,m	;get data for next
	mov	m,c	;write data
	mov	c,a	;set up for next
	inx	h
	ana	a	;is it last
	jnz	Char2	;jmp if no
	mov	m,c	;write end flag

PAGE
;Can LineCursor move right?
	lhld	LineCursor
	mov	a,l
	cpi	4Fh
	jz	Char5	;jmp if no
	cpi	0CFh
	jz	Char5	;jmp if no

;move LineCursor right
	inx	h
	shld	LineCursor

;Display line
Char4:	call	Display
	jmp	Edit

;Increment String1st
Char5:	lhld	String1st
	inx	h
	shld	String1st
	jmp	Char4



;**** Routine BadWait ****
;Will wait for any key (sends message) and then jmp to Begin

BadWait: mvi	c,9	;send message
	lxi	d,BadOpen1
	call	Bdos

	mvi	e,0FDh	;wait for key
	mvi	c,6
	call	Bdos
	jmp	Begin

BadOpen1: dw	NL,NL
	db	'Push any key to continue.'
	dw	NL
Š	db	MsgEnd

PAGE
;**** Subroutine TestFile ****
;Test existing file found on disk
;If MAKEST file then return with Zero Flag set

;Send message
TestFile: 
	call	FileName
	mvi	c,9
	lxi	d,FEmsg
	call	Bdos
	jmp	FEmsgOut

FEmsg:	db	' exists on the selected drive.'
	db	MsgEnd
FEmsgOut: db	0

;Clear area for existing FileName
	lxi	h,Existing
	lxi	b,200h	;more than enough
ClearArea: mvi	m,0
	inx	h
	dcx	b
	mov	a,b
	ora	c
	jnz	ClearArea

;Load existing file
	mvi	c,26	;set DMA address
	lxi	d,Existing
	call	Bdos

	mvi	c,15	;open existing file
	lxi	d,FcbRun
	call	Bdos
Š
	mvi	c,20	;read sequential
	lxi	d,FcbRun
	call	Bdos

PAGE
;Test if embedded "MAKEST end message" is present
	lxi	h,Existing+0FFh-(+EndS9-EndS8)	;first load "MsgEnd" to 
						;byte before embedded message
	mvi	m,MsgEnd
	inx	h	;now set HL to first byte of embedded message
	lxi	d,EndS8
	mvi	b,EndS9-EndS8
Test:	ldax	d
	cmp	m
	jnz	NotFile	;jmp if embedded message not MAKEST's
	inx h !inx d
	dcr	b
	jnz	Test

;This is a MAKEST file - Test if before Version 1.5

	lxi	h,Existing+EndS7-Data	;Get 'V'
	mov	a,m
	cpi	'V'
	jnz	B15V	;jmp if before Version 1.5

;This is a MAKEST file of Version 1.5 or after - Send message
	mvi	c,9
	lxi	d,MFmsg1
	call	Bdos
	jmp	MF2

MFmsg1:	dw	NL
	db	'This file was created by MAKEST '
	db	MsgEnd

MF2:	mvi	c,9			;Send Version number
	lxi	d,Existing+EndS7-Data
	call	Bdos

MF3:	mvi	c,9
	lxi	d,MFmsg3
	call	Bdos
	jmp	MF4

MFmsg3:	dw	NL
	db	'It',39,'s command line is:'
	dw	NL
	db	MsgEnd

MF4:	mvi	c,9	;Send String message
	lxi	d,Existing+String-Data
	call	Bdos

	xra	a	;set zero flag
	ret

ŠPAGE
;Not a MAKEST file - Send message
NotFile: mvi	c,9
	lxi	d,NMmsg
	call	Bdos

	mvi	a,1	;clear zero flag
	ana	a
	ret

NMmsg:	db	'This file was not made by MAKEST. '
	dw	NL
	db	MsgEnd


;File created before MAKEST Version 1.5 - Send message
B15V:	mvi	c,9
	lxi	d,B15Vmsg1
	call	Bdos
	jmp	MF3

B15Vmsg1: dw	NL
	db	'This file was made by MAKEST before Version 1.5  '
	db	27,94,'It should be replaced.',27,113
	db	MsgEnd

PAGE
;**** Write File to Disk ****

;Is there data?
Write:	lxi	h,Buffer
	inx	h
	mov	a,m
	ana	a
	jz	Wait	;jmp if none

;Ask which drive to select
	call HomeIt
	mvi	c,9
	lxi	d,Write2
	call	Bdos
	jmp	Write3

Write2:	db	'Which drive do you want to write '
	db	MsgEnd

Write3:	call	FileName
	mvi	c,9
	lxi	d,Write5
	call	Bdos
	jmp	Write6

Write5:	db	' to?'
	dw	NL
	db	'Select A,B,etc. or <ESC> to return to main menu.'
	dw	NL
	db	MsgEnd

;Wait for key
Write6:	mvi	c,6
	mvi	e,0FDh
	call	Bdos
	cpi	1Bh	;ESC
	jz	Begin
	ani	5Fh	;convert from small to cap.
	cpi	'A'	;is it less than 'A'?
	jc	Write6	;jmp if yes
	cpi	'Q'	;is it less than 'Q'
	jc	Write10	;jmp if yes
	jmp	Write6	;sorry, not A to P

;Convert to drive code and store
Write10: sta	Write17	;store drive letter
	ani	1Fh
	sta	FcbNew

;Create FcbRun 
	call	Create

PAGE
;Clear screen
Write11: call	HomeIt

;Open New File
	mvi	c,22
	lxi	d,FcbRun
	call	Bdos

Š;Test if file opened
	ana	a
	jz	Write40	;jmp if file opened with no problem
	mov	a,h
	cpi	8h
	jz	Write15
	cpi	0
	jnz	BadWait

;No directory space available
	mvi	c,9
	lxi	d,Write12
	call	Bdos
	jmp	BadWait

Write12: dw	NL,NL
	db	'No directory space available.'
	dw	NL
	db	MsgEnd

;Ask if file to be overwritten?
Write15: call	HomeIt
	call	FileName

	mvi	c,9
	lxi	d,Write16
	call	Bdos
	jmp	Write20

Write16: db	' already exists on drive '
Write17: db	'A: '
	dw	NL
	db	'Do you wish to overwrite this file with your new '
	db	'"command" file? (Y/N) '	
	db	MsgEnd

PAGE
;Wait for Erase Answer
Write20: mvi	c,6
	mvi	e,0FDh
	call	Bdos

	cpi	'Y'
	jz	Write22
	cpi	'y'
	jz	Write22
	jmp	Begin

;Erase file
ŠWrite22: mvi	c,19
	lxi	d,FcbRun
	call	Bdos

	ana	a	;test if erased
	jz	Write11	;jmp if erased
	mov	a,h	;test if R/O
	cpi	3
	jz	Write30	;jmp if R/O
	jmp	BadWait

;Ask About Read/Only
Write30: mvi	c,9
	lxi	d,Write31
	call	Bdos
	jmp	Write32

Write31: dw	NL,NL
	db	'The file is Read/Only. Overwrite? (Y/N) '
	db	MsgEnd

;Wait for answer
Write32: mvi	c,6
	mvi	e,0FDh
	call	Bdos

	cpi	'Y'
	jz	Write35
	cpi	'y'
	jz	Write35
	jmp	Begin

;Erase Read/Only
Write35:lda	FcbRun+9	;set FCB to R/W
Š	ani	7Fh
	sta	FcbRun+9
 
	mvi	c,30	;now set file on disk to R/W
	lxi	d,FcbRun
	call	Bdos
	jmp	Write22
PAGE
;**** Load End Flags into Data ****

;Get next address after String
Write40: mvi	b,0	;load number of char to bc
	lda	Buffer+1
	mov	c,a
	lxi	h,String ;load string start adr
	dad	b	;offset

;add end flag of 0h
	mvi	m,0
	inx	h

;add message end flag of $
	mvi	m,'$'
	inx	h


;**** Write Data to Disk ****
	mvi	c,26	;set DMA address
	lxi	d,Data
	call	Bdos

	mvi	c,21	;write data
	lxi	d,FcbRun
	call	Bdos

	mvi	c,16	;close file
	lxi	d,FcbRun
	call	Bdos

	jmp	Begin

**** FCB "to be run" location ***
FcbRun:	ds	1
	db	'EXECST  COM'
	db	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

**** FCB "to be read" location ****
FcbNew:	ds	1
	db	'EXECST  COM'
	db	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
FcbEnd:	ds	1

PAGE
**** Program Data Assembly Area ****

;Set Stack
Data:	lxi	sp,Stack1						;0100h

;Get/Set System Control Block
;Without the following routine the system prompt may display on the
Š;same line last written to. This routine is the same format as found
;in the Osborne EXECST.COM. What it exactly does is unknown by this
;programmer. DR says that an offset of 3Ah is "Reserved for System Use".
	mvi	c,49	;get/set System Control Block			;0103h
	lxi	d,SCB-Data+100h	;location of SCB Parameter Block
	call	Bdos
	mvi	l,0B5h
	mov	a,m
	ori	2
	mov	m,a

;Move String to Default DMA
	lxi	h,String-Data+100h ;address of String when		;0111h
				   ; Data moved to 100h
	lxi	d,80h	;Default DMA start address
Data3:	mvi	b,128	;maximum character count of string
Data4:	mov	a,m	;get String
	stax	d	;store String
	inx	h	;go to next char
	inx	d	;go to next char
	dcr	b	;test if last char
	jnz	Data4-Data+100h ;address of Data4 when Data moved to 100h

;Chain String to Program
	mvi	c,47	;chain to program				;0121h
	mvi	e,0h	;use default CCP values of drive and user number
	jmp	Bdos

;SCB Parameter Block
SCB:	db	3Ah	;offset of SCB					;0128
	db	0	;"get" operation

;Development Area for String
Buffer:	ds	2	;2 bytes for number of characters in string	;012Ah
String:	db	0	;Start of string of characters to be chained.	;012Ch
	db	'$'	;At first command must be 0h then '$'.
	ds	124	;A total of 126 characters.
	ds	2	;String must end with 0h then '$'.

;Unused space
	ds	36							;01CAh

;Version number
EndS7:	db	'Ver. ',xVersion,'.',yVersion,0,'$',0			;01D0h

;Recognition message
EndS8:	db	'This EXECST.COM was created by MAKEST'			;01DBh
EndS9:	db	0							;0200h
PAGE
;**** Routine Diff ****
;Change to a different file name

;Send message
Diff:	call HomeIt
	mvi	c,9
	lxi	d,Diff1
	call	Bdos
	jmp	Diff2

Diff1:	db	'What is the new file name to be?'
	dw	NL
	db	'Enter up to an 8 character file name.'
	dw	NL
	db	MsgEnd

;Setup NewName
Diff2:	lxi	h,NewName
	mvi	m,8	;8 characters max
	inx	h
	inx	h
	mvi	m,0	;no data to start
	jmp	Diff4

NewName: ds	15

;Get file name
Diff4:	lxi	d,NewName
	call	NameEdit
	cpi	0
	jz	Diff10
	cpi	1
	jz	Begin
	cpi	2
	jz	BadWait
	jmp	Begin

;Setup similar to LineEdit
NameEdit: xchg
	shld	StringStart

	lda	WhichRow
	ani	24
	sta	CursorY

	mvi	c,9
	lxi	d,Edit1
	call	Bdos
	jmp	Edit3

PAGE
;Test if no data
Diff10:	lda	NewName+1
	ana	a
	jz	Begin	;Forget it if no data

;Convert small letters to caps
	lxi	h,NewName+2
Diff11:	mov	a,m
	ana	a
	jz	Diff13
	cpi	'a'
	jc	Diff12	;jmp if less than 'a'
	cpi	'z'+1
	jnc	Diff12	;jmp if greater than 'z'
	sui	20h	;convert
	mov	m,a
Diff12:	inx	h
	jmp	Diff11

;Fill FcbRun file name with blanks
Diff13:	mvi	b,8
	mvi	a,' '
	lxi	h,FcbRun+1
Diff15:	mov	m,a
	inx	h
	dcr	b
	jnz	Diff15

;Move new file name to FcbRun
	lxi	h,NewName+2
	lxi	d,FcbRun+1
Diff17:	mov	a,m
	ana	a
	jz	Diff20
	stax	d
	inx	h
	inx	d
	jmp	Diff17

PAGE
;Fill FcbNew file name with blanks
Diff20:	mvi	b,8
	mvi	a,' '
	lxi	h,FcbNew+1
Diff21:	mov	m,a
	inx	h
	dcr	b
	jnz	Diff21

;Move new file name to FcbNew
	lxi	h,NewName+2
	lxi	d,FcbNew+1
Diff23:	mov	a,m
	ana	a
	jz	Diff25
	stax	d
	inx	h
	inx	d
	jmp	Diff23

;Fill FN1 file name with 0's
Diff25:	mvi	b,8
	mvi	a,0
	lxi	h,FN1
Diff27:	mov	m,a
	inx	h
	dcr	b
	jnz	Diff27

;Move new file name to FN1
	lxi	h,NewName+2
	lxi	d,FN1
Diff30:	mov	a,m
	ana	a
	jz	Diff33
	stax	d
	inx	h
	inx	d
	jmp	Diff30

;That's it. Lets go home.
Diff33:	jmp	Begin

	end	100h
