;This version set up for the Osborne Executive by Jim Switz, FOG Executive
;Librarian, 23 January 1984
;
;mage31.asm--mage31 will recover a wordstar file from computer memory
;after a disk-full error, system reset, or other disaster short of a
;complete power loss, but it can only recover that part of the file that
;is in memory when disaster strikes.  it will save the recovered file 
;under a name of your choosing and will display what it is recovering on 
;the screen at the same time.

;how to use mage31--first, do a reset (probably not necessary unless you're
;going to change disks, but it doesn't hurt, so do it anyway).	you can now 
;change disks if you need to.  run mage31.  if you don't specify a filename,
;mage31 will give you instructions.  if you specify a filename (in the form
;mage31 [drive:]filename.typ), mage31 will sign on, give you a last chance
;to back out, and proceed when you hit return.	as mage31 recovers the file,
;it will show what it's recovering on the screen.  if you want to stop the
;recovery at any point, hit any key, and mage31 will save what it has
;already recovered to disk and return you to cp/m.  if you let mage31 run 
;all the way, you will have some junk characters at the end of your file. 
;just delete them with wordstar.

;how to set mage31 for your machine--you need to alter one equate (IMAGE)
;and one db sequence (CLRSCR) to suit your system.  IMAGE must contain the 
;starting address of wordstar's text buffer.  to find this address, you need 
;ddt, wordstar, and a text file.  run wordstar and load the text file.	note 
;the opening text of the file (pick a file with an easily recognizable 
;opening).  now do a system reset (that's right, a reset).  your system will 
;cold boot, but the file you loaded is still there in memory.  load ddt and 
;start looking for the beginning of the file, using the "d" command.  start 
;around 7000h--both the osborne and the morrow wordstars started the text 
;buffer in that area, so it's a good bet.  keep using "d" to display memory 
;and watch the ascii characters on the right of the screen until you see the 
;text that starts your "lost" file.  note the address where the file starts 
;and exit ddt.	put your address in the IMAGE equate, and change the IMAGE
;comment line and the VERSN message at the end of the program to show the 
;make and model of your system.  next check the CLRSCR db sequence near the
;end of the program.  if ESC* doesn't clear your screen and home the cursor
;you'll need to change this sequence to suit your system.  but remember to 
;leave the '$' at the end of whatever you insert.  if you don't have an 80 
;column screen, you'll want to reformat the messages.  voila'--you're done.

;05/29/83--mage version 3.1:  disassembled mage version 3.0 to 8080 source.
;placed starting address of text in an equate (image) so mage31 can be set
;to run on various systems.  fixed bug to allow proper handling of full 
;width (255 character) lines.  added help message if no file specified, 
;caution message on filenames, and chance to abort before recovery starts.
;					   ted silveira

;date unknown--original(?) mage version 3.0 for osborne o1, by chris
;and steve rudek


TPA	EQU	100H
BDOS	EQU	05H
IMAGE	EQU	846DH		;wordstar text start on Osborne Executive    
LF	EQU	0AH
CR	EQU	0DH
TAB	EQU	09H
ESC	EQU	1BH		
RBOOT	EQU	00H		;reboot address
DBUFF	EQU	80H		;cp/m default buffer start
TFCB	EQU	5CH		;transient file control block

	ORG	TPA

START:	LXI	H,0		;save cp/m stack
	DAD	SP
	SHLD	OLDSP
	LXI	SP,STACK	;set up user stack
	LXI	H,IMAGE		;put text start address..
	SHLD	HLSAVE		;..where we can get at it
	LXI	D,CLRSCR	;clear and home..
	CALL	WRTLNC
	LXI	D,VERSN		;..to print version message
	CALL	WRTLNC
	LDA	TFCB+1		;check to see..
	CPI	20H		;..if filename specified
	JZ	HELP		;if no, go to help routine
	LXI	D,SIGNON	;if yes, print sign-on and..
	CALL	WRTLNC
	CALL	RDCON		;..wait for go-ahead from operator	
	LXI	D,TFCB		;delete any old file..
	CALL	DELEFL		;..of the same name and..
	LXI	D,TFCB		;..make a new file..
	CALL	MAKEFL		;..to save the text in
	LXI	D,CLRSCR	;clear and home..
	CALL	WRTLNC		;..so we can view save

SETCT:	MVI	A,0		;zero end-of-text flag
	STA	EOTFLG	
SETCT1:	MVI	A,0		;zero linefeed flag	
	STA	LFFLG	
	MVI	B,80H		;set counter to 128 (80h)
	LHLD	HLSAVE		;point hl to text
	LXI	D,DBUFF		;point de to cp/m default buffer

CKSTOP:	CALL	CKCON		;check for operator cancel
	ORA	A		;if no input..
	JZ	MEMRD		;..then go ahead with text recovery

PAD:	MVI	A,20H		;but if operator cancels, use spaces (20H)..
	STAX	D		;..to pad out..
	INX	D		;..the rest of the record..
	DCR	B
	JNZ	PAD	
	JMP	EXIT		;..and quit	

MEMRD:	MOV	A,M		;get a character from memory (pointed by hl)
	CPI	LF		;is it a linefeed?
	JNZ	DSPLY		;no, skip to display-and-save
	PUSH	PSW		;yes..
	MVI	A,1		;..then set linefeed flag..
	STA	LFFLG	
	POP	PSW		;..and fall through to display-and-save

DSPLY:	STAX	D		;store character in default buffer..
	PUSH	D		;..(pointed by de) and save address on stack
	MOV	E,A		;print character to console screen
	CALL	WRTCON	
	POP	D		;recover the address and..
	INX	D		;..increment so it points to next open slot
	INX	H		;increment text pointer for next character get
	DCR	B		;decrement counter so we'll know if buffer full
	JNZ	CKSTOP		;if not full, loop for next character
	SHLD	HLSAVE		;if buffer full, store text pointer..
	CALL	WRTFL		;..and write out record from default buffer
	LDA	LFFLG		;was there a linefeed character in this batch?
	ORA	A		;(lfflg=1 if there was)
	JNZ	SETCT		;if there was, loop for next record
	LDA	EOTFLG		;if there wasn't, get eotflg..
	INR	A		;..increment it and..
	STA	EOTFLG		;..save it so we know how long since linefeed
	CPI	3		;if only 1 or 2 records without lf, then..
				;..we may be ok (because max ws line=255)..
	JNZ	SETCT1		;..so loop for another record 
				;but if 3 records with no linefeed, then..

EXIT:	CALL	CLOSFL		; close file..
EXIT1:	LHLD	OLDSP		;..restore cp/m stack..
	SPHL
	RET			;..and quit

HELP:	LXI	D,HLPMSG	;get address of help message..
	CALL	WRTLNC		;..print it..
	JMP	EXIT1		;..and quit

RDCON:	MVI	C,1		;get character from console
	CALL	BDOS	
	CPI	0DH		;is it a carriage return?
	JNZ	EXIT1		;if no, then quit
	RET			;if yes, then go ahead

DELEFL:	MVI	C,13H		;delete any existing file of this name
	JMP	BDOS	

MAKEFL:	MVI	C,16H		;make a new file
	JMP	BDOS	

CKCON:	MVI	C,0BH		;check console..
	PUSH	B		;..for any input
	PUSH	D
	PUSH	H
	CALL	BDOS	
	POP	H
	POP	D
	POP	B
	RET

WRTCON:	MVI	C,2		;write a character to the console screen
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	BDOS	
	POP	H
	POP	D
	POP	B
	RET

WRTLNC:	MVI	C,9		;write line to console screen until..
	CALL	BDOS		;..'$' encountered
	RET

WRTFL:	LXI	D,TFCB		;write a record to disk, sequentially
	MVI	C,15H
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	BDOS	
	POP	H
	POP	D
	POP	B
	RET

CLOSFL:	LXI	D,TFCB		;close a file
	MVI	C,10H
	PUSH	B
	PUSH	D
	PUSH	H
	CALL	BDOS	
	POP	H
	POP	D
	POP	B
	RET

EOTFLG:	DS	0001H		;flag/counter to see if end-of-text reached

LFFLG:	DS	0001H		;linefeed flag

HLSAVE:	DS	0002H		;storage for hl pointer

CLRSCR:	DB	ESC,'Z','$'	;the '$' must remain at the end of whatever
				;sequence you put here. escZ is for Osbornes  

VERSN:	DB	TAB,TAB,TAB,TAB,'  >> M A G E <<',CR,LF
	DB	TAB,TAB,TAB,'     Version 3.1  05/29/83',CR,LF,CR,LF
	DB	TAB,TAB,'      This copy set for Osborne Executive  ',CR,LF,'$'

HLPMSG:	DB	CR,LF,TAB,'MAGE31 can recover WordStar files from '
	DB	'memory under most circum-',CR,LF
	DB	TAB,'stances, including system reset but not '
	DB	'complete power loss.',CR,LF,CR,LF
	DB	TAB,'The command form is',CR,LF,CR,LF
	DB	TAB,TAB,'MAGE31 [D:]FILENAME.TYP',CR,LF,CR,LF
	DB	TAB,'[D:] is an optional drive designator.  '
	DB	'FILENAME.TYP is the',CR,LF
	DB	TAB,'mandatory file specification.  The recovered '
	DB	'text will be saved',CR,LF
	DB	TAB,'under this name.',CR,LF,CR,LF
	DB	TAB,'CAUTION:  MAGE31 will first delete any existing '
	DB	'file of the name',CR,LF
	DB	TAB,'specified in the command line.  If you try '
	DB	'to recover your text',CR,LF
	DB	TAB,'under its original name, you will wipe '
	DB	'out any earlier version.',CR,LF
	DB	TAB,'Use a new file name (like RESCUED.TXT), '
	DB	'and keep the earlier',CR,LF
	DB	TAB,'version in case your recovery is incomplete.$'

SIGNON:	DB	CR,LF,TAB,'MAGE will recover WordStar files from '
	DB	'memory after almost any',CR,LF
	DB	TAB,'accident, short of a complete power loss.  '
	DB	'It will save the re-',CR,LF
	DB	TAB,'covered text under the name '
	DB	'you have specified.',CR,LF,CR,LF
	DB	TAB,'CAUTION:  MAGE will first delete any '
	DB	'existing files that have',CR,LF
	DB	TAB,'the name you have specified.  If '
	DB	'you are using the original name',CR,LF
	DB	TAB,'of your lost file, you will '
	DB	'WIPE OUT any earlier version.  It is',CR,LF
	DB	TAB,'better to choose a new name '
	DB	'(like RESCUED.TXT) for the rescued',CR,LF
	DB	TAB,'file so you will have the earlier '
	DB	'version as a backup.',CR,LF,CR,LF
	DB	TAB,'Once MAGE starts running, it will display '
	DB	'what it is recovering',CR,LF
	DB	TAB,'on the screen.  You can end the '
	DB	'recovery at any time (once you ',CR,LF
	DB	TAB,'have what you want) by pressing any key.'
	DB	CR,LF,CR,LF,CR,LF,CR,LF
	DB	TAB,'PRESS <RETURN> TO BEGIN',CR,LF
	DB	TAB,'PRESS ANY OTHER KEY TO ABORT$'
	
OLDSP:	DS	2		;storage for cp/m stack pointer

	DS	10H
STACK:	DB	0

	END
