
*-----------------------------------------------------------------------*
*									*
*		Commodore FD to _LVO file converter			*
*									*
*		By Toby W.Simpson					*
*		Copyright 1991 Toby W.Simpson, All rights reserved.	*
*									*
*-----------------------------------------------------------------------*
;		
		section	ConvertFD,code
;
; ---- IO Buffer sizes ....
RC_BUFFSIZE:	equ	100			; 100 bytes file buffer
;
		bra	BEGIN
;
; ---- Embedded (C)'s ....
VERSION:	macro
		dc.b	"1.14"
		endm
Title:		dc.b	"Amiga FD to _Lib.i converter",0
CopyRight:	dc.b	"Copyright 1991 Toby W.Simpson, All rights reserved",0
Author:		dc.b	"Toby W.Simpson",0
Date:		dc.b	"January 1991",0
		VERSION
		dc.b	0
;
; ---- Includes ....
		incdir	"inc:"
;
; ---- Since at this point you probably don't have the _lib.i files,
;      you need the funcdef.i in order to make the exec_lib.i file
;      from commodore actually work. If you DO have old _lib.i files
;      (From devpac) - include them and eliminate the funcdef.i line ....
		include	"exec/funcdef.i"
		include	"exec/exec_lib.i"
		include	"dos/dos_lib.i"
		even
;
; ---- Startup code ....
;      See after this for the startup.i code
;
		include	"startup.i"
		even
;
; -----------------------------------------------------------------------
;
;	Program loop.
;
InFile:		dcb.b	40,0
OutFile:	dcb.b	40,0
;
; ---- It adds this to the output file ....
OutTerm:	dc.b	"_lib.i",0
;
DOS:		macro	
		move.l	ST_DosBase,a6
		jsr	_LVO\1(a6)
		endm

START:		lea	FD_Startup(pc),a0
		jsr	PrintMessage
		tst.l	ST_Message
		bne	ST_MustCLI
;
; ---- Pull out filenames ....
; =====================================================================
;	THIS CHUNK OF CODE IS GARBAGE. 
;	If you want to re-write the marked chunk (in ==='s) then all you
;	need to know is that on entry to this bit, ST_Command contains the
;	address of the start of all parameters, and ST_Bytes contains the
;	number of bytes in the parameter.
;	When you recall the Infile and Outfile, place them in the two
;	buffers InFile and OutFile.
		move.l	ST_Command,a0
		move.l	ST_Bytes,d0
		subq.l	#$01,d0
		beq	ST_UsageErr
ST_SearchIn:	cmp.b	#$20,(a0)+
		bne	ST_FoundA
		dbra	d0,ST_SearchIn
		bra	ST_UsageErr		; No Correct <input>
ST_FoundA:	lea	InFile(pc),a1
		move.b	-1(a0),(a1)+
		moveq	#$00,d4
ST_CopyFN:	move.b	(a0)+,d1
		subq.l	#$01,d0
		addq.l	#$01,d4
		cmp.l	#22,d4
		beq	ST_DoneA		; Line overflow.
		tst.l	d0
		beq	ST_DoneA
		cmp.b	#$20,d1
		beq	ST_DoneA
		move.b	d1,(a1)+
		bra	ST_CopyFN		; Do input FN.
ST_DoneA:	clr.b	(a1)+
		tst.l	d0
		beq	ST_AssumeOut		; Assume an output FN
;
; ---- Fetch an output FN ....
ST_SearchOut:	cmp.b	#$20,(a0)+
		bne	ST_FoundB
		dbra	d0,ST_SearchOut
		bra	ST_AssumeOut		; No Correct <input>
ST_FoundB:	lea	OutFile(pc),a1
		move.b	-1(a0),(a1)+
		moveq	#$00,d4
ST_CopyFN2:	move.b	(a0)+,d1
		subq.l	#$01,d0
		addq.l	#$01,d4
		cmp.l	#22,d4
		beq	ST_DoneB		; Line overflow.
		tst.l	d0
		beq	ST_DoneB
		cmp.b	#$20,d1
		beq	ST_DoneB
		move.b	d1,(a1)+
		bra	ST_CopyFN2		; Do input FN.
ST_DoneB:	clr.b	(a1)+
		bra	ST_DoConv
;
; ---- Output assumption code ....
ST_AssumeOut:	lea	InFile(pc),a0
		lea	OutFile(pc),a1
ST_CopyInOut:	move.b	(a0)+,(a1)+
		bne	ST_CopyInOut
		lea	OutTerm(pc),a0
		sub.l	#$01,a1
ST_CopyTermOut:	move.b	(a0)+,(a1)+
		bne	ST_CopyTermOut		; Put a _lib.i on.
;
; ====================================================================
;
; ---- Do the conversion ....
ST_DoConv:	jsr	ConvertFD		; Confert to FD.
		rts
ST_MustCLI:	lea	ST_CLIMsg(pc),a0
		jsr	PrintMessage
		rts
ST_UsageErr:	lea	ST_Usage(pc),a0
		jsr	PrintMessage
		rts
ST_CLIMsg:	dc.b	"_MUST_ be run from the CLI.",10,0
ST_Usage:	dc.b	"Usage: ConvertFD <Input> [<Output>]",10,0
FD_Startup:	dc.b	"ConvertFD Version "
		VERSION
		dc.b	" by Toby Simpson. Copyright 1991 Toby Simpson",10,0
		even
;
; -----------------------------------------------------------------------
;
; FD files to _lib.i converter program routines.
; Works as follows:
;
;   ID's library, base variable from the initial comment and ##base.
;   Then works through file processing library entries, ##public and
;   ##private are effectively ignored, bar a comment on the LVO line
;   if a function is private. The current bias is worked out as the
;   program progresses, with ##bias statements altering it. All bar
;   the first * comment are passed directly to the output file with
;   ; colons instead. Program stops working on reciept of the ##end
;   directive.
;
ConvertFD:	jsr	CFD_DoWork		; Do everything now.

		
CFD_Quit:	moveq	#$00,d0
		rts				; Signals OK and returns
;
; ---- Keywords understood by the parser ....
FD_ValidKW:	dc.b	"*",0,"##base",0,"##bias",0
		dc.b	"##public",0,"##private",0,"##end",0
		dc.b	0
;
; ********************************************************************
;
;	File Parser routines from Config File reader 
;	Copyright T.Simpson 1990
;
; -----------------------------------------------------------------------
;
CFD_DoWork:	lea	FD_ValidKW(pc),a1
		move.l	a1,RC_Keywords
;
; ---- Open input file ....
		lea	InFile(pc),a0
		move.l	a0,d1
		move.l	#1005,d2
		DOS	Open			; Open the file.
		move.l	d0,RC_InChannel		; Store channel
		beq	RC_NoFile		; No input file.
;
; ---- Open output file ....
		lea	OutFile(pc),a0
		move.l	a0,d1
		move.l	#1006,d2
		DOS	Open			; Open the file.
		move.l	d0,RC_OutChannel	; Store channel
		beq	RC_NoOut		; No Output file.
;
; ---- Initialise buffers ....
		clr.w	RC_ByteCount
		clr.l	RC_OutStat
		clr.b	RC_CommentIn		; Any comments yet
		move.l	#RC_BUFFSIZE,RC_BytesEach
		clr.l	RC_Bias
;
; ---- The ConvertFD bit ....
CFD_Main:	bsr	RC_FetchWord		; Find a word.
		cmp.l	#-1,d0
		beq	RC_End			; Couldn't.

		cmp.b	#"*",RC_WordBuffer
		beq	CFD_Comment
		cmp.b	#"#",RC_WordBuffer
		beq	CFD_CheckKW
;
; ---- Got a command. Copy it out now ....
CFD_Alpha:	lea	FD_LVOString(pc),a0
		bsr	CopyToOut		; Copy LVO Start out
		cmp.l	#-1,d0
		beq	RC_OutError
		lea	RC_OutWord(pc),a1
		lea	RC_WordBuffer(pc),a0
		moveq	#127,d4			; Max chars.
CFD_CopyFunc:	move.b	(a0)+,d0
		beq	CFD_DoneFunc
		cmp.b	#"(",d0
		beq	CFD_DoneFunc		; Done function.
		move.b	d0,(a1)+
		dbra	d4,CFD_CopyFunc
;
; ---- Error, print ....
		lea	CFD_OverFlow(pc),a0
		jsr	PrintMessage
		bra	RC_End			; Close and quit.
CFD_OverFlow:	dc.b	"Fatal Error: Function overflowed.",10,0
		even
RC_OutError:	lea	CFD_WriteErr(pc),a0
		jsr	PrintMessage
		bra	RC_End
CFD_WriteErr:	dc.b	"Fatal Error: Output file write fail.",10,0
		even
;
; ---- Now tab up and put in an equate ....
CFD_DoneFunc:	clr.b	(a1)+
		lea	RC_OutWord(pc),a0
		bsr	CopyToOut		; Copy out func name
		cmp.l	#-1,d0
		beq	RC_OutError
		lea	FD_EQUString(pc),a0
		bsr	CopyToOut
		move.l	RC_Bias,d2		; Bias value.
		add.l	#$06,RC_Bias
		lea	RC_OutWord(pc),a1	; Put data here
		jsr	OutDec32		; Convert to dec.
		lea	RC_OutWord(pc),a0
		bsr	CopyToOut		; Copy bias out.
		cmp.l	#-1,d0
		beq	RC_OutError
		lea	RC_CRLF(pc),a0
		bsr	CopyToOut		; Linefeed.
		cmp.l	#-1,d0
		beq	RC_OutError
		bra	CFD_Main		; Try next one.
;
; ---- Output strings ....
FD_LVOString:	dc.b	"_LVO",0		; Function header
FD_EQUString:	dc.b	$09,"equ",$09,"-",0	; Offset header
RC_CRLF:	dc.b	10,0			; Linefeed character
;
;
;	KEYWORD HANDLERS (In file directives)
;
CFD_CheckKW:	bsr	RC_CheckWord		; ID it.
		tst.l	d0
		bne	CFD_Main		; Couldn't. Ignore.
		tst.l	d4
		beq	CFD_Comment		; A comment line.
		cmp.b	#$01,d4
		beq	CFD_FFbase		; Base
		cmp.b	#$02,d4
		beq	CFD_FFbias		; Bias change/set
		cmp.b	#$03,d4
		beq	CFD_FFpublic		; Public funcs.
		cmp.b	#$04,d4
		beq	CFD_FFprivate		; Private funcs.
		cmp.b	#$05,d4
		beq	CFD_FFend		; End of file.
		bra	CFD_Main		; Unidentified.
;
; ---- Keyword handlers ....
;	1. comments.
CFD_Comment:	bsr	RC_SkipToEOL
		cmp.l	#-1,d0
		beq	RC_End			; EOF reached.
		lea	VD_SkipCom(pc),a0
		jsr	PrintMessage
		bra	CFD_Main
VD_SkipCom:	dc.b	".",0
;
;	2. base.
CFD_FFbase:	bsr	RC_SkipToEOL
		cmp.l	#-1,d0
		beq	RC_End			; EOF reached.
		lea	VD_SkipCom(pc),a0
		jsr	PrintMessage
		bra	CFD_Main
;
; 	3. bias.
CFD_FFbias:	bsr	RC_FetchWord
		cmp.l	#-1,d0
		beq	RC_End			; EOF reached.
		tst.b	RC_WordBuffer
		beq	CFD_Main
		lea	RC_WordBuffer(pc),a0
		jsr	InDec16			; Convert to decimal
		and.l	#$ffff,d0
		move.l	d0,RC_Bias		; Set new bias.
		lea	VD_Bias(pc),a0
		jsr	PrintMessage
		move.l	RC_Bias,d2
		lea	RC_WordBuffer(pc),a0
		jsr	OutDec32
		lea	RC_WordBuffer(pc),a0
		jsr	PrintMessage
		lea	RC_CRLF(pc),a0
		jsr	PrintMessage		; Prompt on vdu
		bra	CFD_Main
VD_Bias:	dc.b	10,"Library offset @",0
;
;	4. private
CFD_FFprivate:	st.b	RC_Private		; Private functions.
		lea	VD_Pri(pc),a0
		jsr	PrintMessage
		bra	CFD_Main
VD_Pri:		dc.b	"[pri]",0
;
;	5. Public
CFD_FFpublic:	clr.b	RC_Private		; Public functions.
		lea	VD_Pub(pc),a0
		jsr	PrintMessage
		bra	CFD_Main
VD_Pub:		dc.b	"[pub]",0
;
; 	6. End.
CFD_FFend:	lea	FD_EndString(pc),a0
		jsr	CopyToOut		; Place EOF string.
		lea	VD_End(pc),a0
		jsr	PrintMessage
		bra	RC_End			; Quit.
FD_EndString:	dc.b	10,"; End of _libfile",10,0
VD_End:		dc.b	10,"End of _libfile.",10,0
		even
;
;
;	SUPPORT ROUTINES FOR PARSER.
;
; ---- ID word from config list ....
RC_CheckWord:	moveq	#$00,d4
		move.l	RC_Keywords,a1
		lea	RC_WordBuffer(pc),a0
RC_IDWord:	bsr	RC_Compare		; Compare two strings
		tst.b	d0
		beq	RC_CheckYes		; ID'd keyword.
RC_NextKW:	tst.b	(a1)+
		bne	RC_NextKW
		addq.l	#$01,d4
		tst.b	(a1)			; End of list?
		beq	RC_CheckDone		; Unidentified keyword		
		bra	RC_IDWord		; Try this one now...
RC_CheckDone:	st.b	d0
		rts				; No.
RC_CheckYes:	moveq	#$00,d0
		rts				; Yes.
;
; ---- Simple compare routine ....
RC_Compare:	movem.l	a0-a1,-(sp)		; Store work regs.
RC_CLoop:	tst.b	(a0)
		beq	RC_CEnd			; End of compare
		cmp.b	(a0)+,(a1)+
		beq	RC_CLoop
RC_CFail:	st.b	d0
RC_CQUIT:	movem.l	(sp)+,a0-a1
		rts				; Signal fail and end
RC_CEnd:	tst.b	(a1)
		bne	RC_CFail
		moveq	#$00,d0
		bra	RC_CQUIT		; Signal match and return
;
; ---- End and closedown processors ....
RC_End:		bsr	PurgeOut		; Purge output buffer
		move.l	RC_OutChannel,d1
		DOS	Close			; Close up
		move.l	RC_InChannel,d1
		DOS	Close			; Close up
		moveq	#$00,d0
		bra	RC_QUIT			; Signal OK and return
RC_NoOut:	move.l	RC_InChannel,d1
		DOS	Close			; Close other one
		lea	RC_NoOF(pc),a0
		jsr	PrintMessage
		st.b	d0
		rts
RC_NoIF:	dc.b	"Can't open input file.",10,0
		even
RC_NoFile:	lea	RC_NoIF(pc),a0
		jsr	PrintMessage
		st.b	d0
RC_QUIT:	rts				; Signal fatal and return
RC_NoOF:	dc.b	"Can't open output file.",10,0
		even
;
; ---- Fetch one word from config buffer ....
RC_FetchWord:	clr.b	RC_WordBuffer		; Invalidate word
		clr.b	RC_QuoteOn		; Quotes.
		bsr	RC_FetchChar
		cmp.l	#-1,d0
		beq	RC_EndOfFile
		cmp.b	#$20,d0
		bls	RC_FetchWord
		cmp.b	#$7f,d0
		bhs	RC_FetchWord		; All invalid chars
;
; ---- OK! We have a valid start char ....
		lea	RC_WordBuffer(pc),a5
		cmp.b	#$22,d0
		beq	RC_QuoteCode		; Quote handler
		move.b	d0,(a5)+		; Store first char
RC_GetAll:	bsr	RC_FetchChar		; Fetch a byte.
		cmp.l	#-1,d0
		beq	RC_EndOfFile
		cmp.b	#$22,d0
		beq	RC_QuoteCode		; Handle quotes.
		cmp.b	#$20,d0
		bne	RC_NoSpace		; Not space
		tst.b	RC_QuoteOn
		beq	RC_Terminate
RC_NoSpace:	cmp.b	#$20,d0
		blo	RC_Terminate
		cmp.b	#$7f,d0
		bhs	RC_Terminate		; EOW conditions
		move.b	d0,(a5)+		; Store character
		cmp.l	#RC_EndWordBuf,a5
		beq	RC_WordOverflow		; Word overflow
		bra	RC_GetAll
RC_QuoteCode:	not.b	RC_QuoteOn		; Toggle quote code.
		bra	RC_GetAll		; Back to loop.
RC_Terminate:	clr.b	(a5)			; NULL terminate word
		moveq	#$00,d0
		rts
RC_EndOfFile:	rts 
RC_WordOverflow:bsr	RC_SkipToEOL
		rts
;
; ---- Skip to end of line ....
RC_SkipToEOLB:	bsr.s	RC_SkipToEOL
		cmp.l	#-1,d0
		beq	RC_EndOfFile
		bra	RC_FetchWord		; For non JSR call
RC_SkipToEOL:	bsr	RC_FetchChar
		cmp.l	#-1,d0
		beq	RC_EOF			; EOF reached
		cmp.b	#$0a,d0
		bne	RC_SkipToEOL
RC_EOF:		rts
;
; ---- Fetch one character ....
RC_FetchChar:	tst.w	RC_ByteCount		; Buffer empty?
		beq	RC_FetchMore		; Yup, get more
		lea	RC_Buffer(pc),a0	; Addr of buffer
		moveq	#0,d0
		move.w	RC_BytesIn,d0
		sub.w	RC_ByteCount,d0
		move.b	0(a0,d0.w),d0		; Fetch buffered char.
;		tst.b	RC_QuoteOn
;		bne	RC_NoLC			; Don't touch, quotes!
;		cmp.b	#"A",d0
;		blo	RC_NoLC
;		cmp.b	#"Z",d0
;		bhi	RC_NoLC
;		add.b	#$20,d0			; Force LC
RC_NoLC:	sub.w	#$01,RC_ByteCount
		rts				; Next char & return
;
RC_FetchMore:	lea	RC_Buffer(pc),a0
		move.l	a0,d2
		move.l	RC_BytesEach,d3
		move.l	RC_InChannel,d1
		DOS	Read			; Read some characters
		cmp.l	#-1,d0
		beq	RC_EndFile		; Error.
		move.w	d0,RC_BytesIn
		move.w	d0,RC_ByteCount		; Buffer fullish
		tst.w	d0
		beq	RC_EndFile
		bra	RC_FetchChar		; All done!		
RC_EndFile:	move.l	#-1,d0
		rts				; Error & return.
;
; ---- Output buffer managers ....
;
;	1. One NULL terminated string to output.
CopyToOut:	move.b	(a0)+,d0
		beq	CTO_End			; End
		bsr	OutCharacter		; Output this chr
		cmp.l	#-1,d0
		beq	CTO_End
		bra	CopyToOut
CTO_End:	rts
;
;	2. One character (d0) to output buffers.
OutCharacter:	movem.l	a0/d1-d4/d7,-(sp)
		cmp.w	#RC_BUFFSIZE,RC_OutStat
		beq	OC_BuffFull
OC_PlaceHere:	lea	RC_OutBuffer(pc),a0
		move.w	RC_OutStat,d1
		move.b	d0,0(a0,d1.w)		; Store character.
		add.w	#$01,RC_OutStat		; Next Psn.
OC_Quit:	movem.l	(sp)+,a0/d1-d4/d7
		rts
OC_BuffFull:	move.l	d0,d7
		moveq	#$00,d3
		move.w	RC_OutStat,d3
		move.l	RC_OutChannel,d1
		lea	RC_OutBuffer(pc),a0
		move.l	a0,d2
		DOS	Write			; Write this block
		cmp.l	#-1,d0
		beq	OC_Quit			; ERROR.
		clr.w	RC_OutStat		; Reset counter
		move.l	d7,d0
		bra	OC_PlaceHere
;
; 	3. Purge buffer.
PurgeOut:	moveq	#$00,d3
		move.w	RC_OutStat,d3
		move.l	RC_OutChannel,d1
		lea	RC_OutBuffer(pc),a0
		move.l	a0,d2
		DOS	Write			; Write this block
		rts
;
; ---- Variables used in config routines ....
RC_OutBuffer:	dcb.b	RC_BUFFSIZE+1,0		; Output buffer
RC_Buffer:	dcb.b	RC_BUFFSIZE+1,0		; Small buffer
		even
RC_WordBuffer:	dcb.b	150,0			; Small buffer
RC_EndWordBuf:	dc.w	0			; End word buffer
RC_ByteCount:	dc.w	0			; Bytes in buffer
RC_BytesEach:	dc.l	RC_BUFFSIZE
RC_QuoteOn:	dc.w	0			; Quote toggle flag
RC_Keywords:	dc.l	0			; Address of kw table
RC_Return:	dc.l	0			; Address of return area
RC_Bytes:	dc.l	0			; Size of return area
RC_InChannel:	dc.l	0			; File handle.
RC_OutChannel:	dc.l	0			; Output channel
RC_BytesIn:	dc.l	0			; Bytes in to work with
RC_OutStat:	dc.l	0			; Bytes in o/p buffer
RC_CommentIn:	dc.w	0			; Comment counter
RC_Bias:	dc.l	0			; Current offset bia
RC_OutWord:	dcb.b	256,0
RC_Private:	dc.w	0			; Priv/Pub flag
;
; ---- Decimal number handlers ....
;	(Rubbish, but works)
OutDec32:	lea	OD_Dividor(pc),a0	; Address of dividor
		moveq	#$03,d4			; Iterations
OD_DecLoop:	move.l	(a0)+,d1		; Get dividor
		clr.l	d0
OD_DigitLoop:	sub.l	d1,d2			; Subtract..
		bcs	OD_DecOver
		addq	#$01,d0			; Digit
		bra	OD_DigitLoop
OD_DecOver:	add.l	d1,d2
		add.b	#$30,d0
		move.b	d0,(a1)+
		dbra	d4,OD_DecLoop
		clr.b	(a1)+
		rts
OD_Dividor:	dc.l	1000,100,10,1
;
; Indec - 16 bit decimal string > number conversion routine
; (C) TWS 1989. a0 address of number, d0 is returned value.
;	Revision History:
;	01-01-91  Tidied, Null rather than CR detection, faster code.
;
InDec16:	movem.l	d1-d3/a0-a1,-(sp)
		move.l	a0,a1
		moveq	#$00,d0			; Length of string
		moveq	#$00,d1			; Final result
ID16_FLen:	tst.b	(a0)+
		bne	ID16_FLen
		subq.l	#$01,a0
		moveq	#$01,d2			; Units to start with
ID16_ToDec:	move.b	-(a0),d0
		sub.b	#$30,d0			; ASCII > Dec
		mulu	d2,d0			; get this mul.		
		add.l	d0,d1			; Add to result
		mulu	#$0a,d2			; ..tens, hundreds etc..
		moveq	#$00,d0
		cmp.l	a0,a1
		bne	ID16_ToDec
		move.l	d1,d0
		movem.l	(sp)+,d1-d3/a0-a1
		rts
;
; -----------------------------------------------------------------------
;
		end
