; maildc/asm - kjw/bqsd - version 2.00 - 01/83
;
; revised 02/23/83 - kjw
;
	SUBTTL	'<maildc/asm - CONVERT module>'
;
;	system data usage
;
;	+1		- type of file being converted
;	+7,8,9		- source record #
;	+10,11,12	- current physical record #
;	+13		- offset in I/O buffer
;	+14,15,16	- current adder record #
;	+17,18,19	- physical record adder
;	+20		- data offset in adder
;	+21		- drive # for convert file
;	+22,23		- convert table address
;	+24,25,26	- offset into file for postman
;	+32,33,34	- # records converted
;
	PAGE
;
;	convert utiltiy
;
CONVERT	BIT	7,(IY+0)	;adder available?
	LD	HL,MSGCC	;start of error message
	JP	Z,CANNOT	;cannot convert!
;
	CALL	INITCNT		;clear counters
	LD	HL,MSGC1	;file type to convert
	CALL	DISPLAY		;display prompt
	LD	B,1		;single key input
	CALL	GETSTR		;from keyboard
	JP	C,MENU		;go on BREAK
	JR	Z,CONVERT	;go on nil input
	CALL	UCASE		;make upper case
	CP	'X'		;alternate BREAK?
	JP	Z,MENU		;go if yes!
	SUB	'1'		;remove ascii
	JR	C,CONVERT	;go if invalid
	CP	6		;1-6?
	JR	NC,CONVERT	;go if invalid, ask again
	LD	(IY+1),A	;save file type
;
GETFIL	LD	HL,MSGC2	;'filespec to convert?'
	CALL	DISPLAY		;display prompt
	LD	B,24		;max input length
	CALL	GETSTR		;get from keyboard
	JP	C,MENU		;go on BREAK
	JR	Z,GETFIL	;go on nil input
	LD	A,CR		;carriage return to video
	CALL	VOUT		;display
;
;	convert input to upper case
;
	PUSH	BC		;save length
	PUSH	HL		;save string start
TOUCS	LD	A,(HL)		;get string byte
	CALL	UCASE		;make upper case
	LD	(HL),A		;update
	INC	HL		;bump pointer
	DJNZ	TOUCS		;continue for length
	POP	HL		;restore start
	POP	BC		;restore length
;
;	open file to see if it exists
;
	LD	DE,FCBX		;extra file block
	LD	BC,32		;max length
	PUSH	DE		;save FCB start
	LDIR			;move name into block
	POP	DE		;DE => name
	LD	HL,BUFFX	;extra file buffer
;
	OPEN$			;locate the file
	JP	NZ,CERROR	;go on error!
;
	LD	HL,MSGC4	;'converting file'
	CALL	DISPLAY		;display message
;
;	begin conversion
;
	XOR	A		;load zero
	LD	(IY+7),A	;set record # source
	LD	(IY+8),A
	LD	(IY+9),A	;3 byte record #
	LD	A,(IY+4)	;get record # adder
	LD	(IY+14),A	;set start record #
	LD	A,(IY+5)
	LD	(IY+15),A
	LD	A,(IY+6)
	LD	(IY+16),A
	LD	A,(IY+1)	;get file type
	AND	7		;low 3 bits
	PUSH	AF		;save type
	ADD	A,A		;*2
	LD	C,A		;pass to C
	LD	B,0		;BC = offset
	LD	HL,TABLEC1	;lookup table for conv
	ADD	HL,BC		;HL => vector
	LD	A,(HL)		;get lsb vector
	LD	(IY+22),A	;save it
	INC	HL		;bump table
	LD	A,(HL)		;get msb vector
	LD	(IY+23),A	;save it
	POP	AF		;get type back
	OR	A		;postman?
	JR	NZ,CONVST	;go start if not
;
;	postman keeps the data in the first record
;
	LD	DE,FCBX		;extra FCB
	LD	BC,REWIND	;3 00's
;
	POSN$			;position to record
	JP	NZ,CERROR	;go if error
	READ$			;read first record
	JP	NZ,CERROR	;go on error
;
	LD	HL,BUFFX	;I/O buffer
	LD	DE,8		;offset to start rec #
	ADD	HL,DE		;HL => first record
	LD	A,(HL)		;get LSB
	LD	(IY+26),A	;save LSB
	INC	HL		;bump pointer
	LD	A,(HL)		;get MSB
	LD	(IY+25),A	;save MSB
	XOR	A		;load zero
	LD	(IY+24),A	;set MSB to 0
;
;	load first buffer for quick writes
;
CONVST	LD	B,(IY+14)	;get record # adder
	LD	H,(IY+15)
	LD	L,(IY+16)
	CALL	COMPSEC		;compute phys sector
	LD	(IY+20),A	;save byte offset
	SET	6,(IY+1)	;set sector in memory
	PUSH	AF		;save offset
	CALL	INCBHL		;+1 for index
	POP	AF		;restore offset
	LD	(IY+17),B	;update current sector
	LD	(IY+18),H
	LD	(IY+19),L
	OR	A		;rel byte 0?
	JR	Z,CONVLP	;no read if yes
	LD	DE,FCBA		;adder FCB address
	LD	BC,SYSTEM+17	;point to record
;
	POSN$			;position to record
	JP	NZ,CERROR	;go if error
	READ$			;load I/O buffer
	JP	NZ,CERROR	;go if any errors!
;
;	setup loop to convert file
;
CONVLP	CALL	STROBE		;strobe keyboard
	CP	BREAK		;break key?
	JP	Z,ABORT		;yes, abort operation
;
	CALL	GETSRC		;get source record
	JP	C,CONVEND	;done, go!
	JP	NZ,CERROR	;go on error
;
;	check if nil record
;
	LD	C,(IY+13)	;offset in source record
	LD	B,0		;BC = offset
	LD	HL,BUFFX	;source buffer start
	ADD	HL,BC		;HL => record
	LD	A,(IY+1)	;get file type
	AND	7		;low 3 bits only
	JR	Z,CKPOST	;check postman
	CP	5		;powermail?
	JR	NZ,CONTPUT	;continue if not
;
CKPMAIL	LD	A,(HL)		;get first byte record
	INC	A		;FF nil record?
	JR	Z,NEXSRC	;yes, go next source rec
	JR	CONTPUT		;else convert it
;
CKPOST	LD	A,(HL)		;get first byte
	OR	A		;first byte 00?
	JR	NZ,CONTPUT	;nope, convert!
	INC	HL		;bump to second byte
	LD	A,(HL)		;get it
	DEC	HL		;put it back
	INC	A		;second byte FF?
	JR	Z,NEXSRC	;yes, go next record!
;
CONTPUT	CALL	PUTDES		;write to adder
	JP	NZ,CERROR	;go on error
;
;	bump record #'s
;
	CALL	ADDCNTA		;bump A counter
	LD	B,(IY+4)	;get # records in adder
	LD	H,(IY+5)
	LD	L,(IY+6)
	CALL	INCBHL		;increment record #
	LD	(IY+4),B	;update
	LD	(IY+5),H
	LD	(IY+6),L
	LD	B,(IY+14)	;get record # adder
	LD	H,(IY+15)
	LD	L,(IY+16)
	CALL	INCBHL		;increment rec #
	LD	(IY+14),B	;update
	LD	(IY+15),H
	LD	(IY+16),L
;
NEXSRC	LD	B,(IY+7)	;get source rec #
	LD	H,(IY+8)
	LD	L,(IY+9)
	CALL	INCBHL		;increment BHL
	LD	(IY+7),B	;update
	LD	(IY+8),H
	LD	(IY+9),L
	JP	CONVLP		;go next record
;
;	error on convert
;
CERROR	CALL	ERROR		;display error message
	LD	HL,MSG2		;'key to continue'
	CALL	DISPLAY		;display message
	CALL	INKEY		;wait for a key
	JR	CONV2		;display # converted
;
;	convert completed
;
CONVEND	LD	DE,FCBA		;adder FCB address
	LD	BC,SYSTEM+17	;point to rec #
;
	POSN$			;position to record
	JR	Z,CONV1		;go if no error
	CP	1CH		;eof?
	JR	Z,CONV1		;go if yes
	CP	1DH		;beyond eof?
	JP	NZ,CERROR	;go if not
CONV1	WRITE$			;flush partial buffer
	JP	NZ,CERROR	;go if error!
;
CONV2	LD	B,(IY+32)	;get # records converted
	LD	H,(IY+33)
	LD	L,(IY+34)
	LD	DE,MSGC6A	;text to load ascii
	CALL	BINASC		;binary => ascii
	LD	HL,MSGC6	;start of message
	CALL	DISPLAY		;display message
	CALL	INKEY		;wait for a key
	JP	MENU		;back to menu
;
;	compute physical sector # of source record
;
COMPSRC	LD	A,(IY+1)	;get file type
	AND	7		;low 3 bits only
	CP	3		;RS expanded?
	JR	Z,COMPEXP	;yes, go!
	CP	4		;RS compressed?
	JR	Z,COMPCOM	;yes, go!
;
	CALL	COMPSEC		;compute phys sector
	LD	C,A		;save offset
	LD	A,(IY+1)	;get file type again
	AND	7
	LD	A,C		;get offset back
	RET	NZ		;go if not postman
	LD	C,(IY+24)	;get postman offset
	LD	D,(IY+25)
	LD	E,(IY+26)
	PUSH	AF		;save A
	CALL	ADDIT		;add BHL => CDE
	POP	AF		;restore
	RET			;done
;
COMPEXP	CALL	COMPSEC		;compute phys sector
	OR	A		;first boundary?
	RET	Z		;yes, done!
	LD	A,7FH		;offset to record 2
	RET			;done!
;
COMPCOM	LD	A,3		;3 records / sector
	CALL	TDIVD		;divide BHL / 3
	OR	A		;no remainder?
	RET	Z		;yes, done!
	DEC	A		;remainder =1?
	LD	A,55H		;record 2 offset
	RET	Z		;done!
	LD	A,0AAH		;record 3 offset
	RET			;done!
;
;	move record from source file => adder file
;
MOVREC	CALL	CLRDATA		;clear buffer
	LD	HL,BUFFA	;adder I/O buff
	LD	C,(IY+20)	;get adder offset
	LD	B,0		;BC = offset
	ADD	HL,DE		;HL => dest in adder
	EX	DE,HL		;DE => dest
	LD	HL,BUFFER	;cleared record
	LD	BC,128		;length
	LDIR			;move it in
;
	LD	HL,BUFFX	;source I/O buffer
	LD	E,(IY+13)	;offset to source record
	LD	D,0		;DE = offset
	ADD	HL,DE		;HL => source
	EX	DE,HL		;DE => source
	LD	HL,BUFFA	;adder buffer
	LD	C,(IY+20)	;offset in adder
	LD	B,0		;BC = offset
	ADD	HL,BC		;HL => dest
	LD	C,(IY+22)	;get table start
	LD	B,(IY+23)	;BC => lookup table
	PUSH	IY		;save IY
	PUSH	BC		;pass BC => IY
	POP	IY		;IY => table
;
MOVELP	LD	A,(IY+0)	;get table entry
	CP	-1		;terminator?
	JR	Z,MOVEND	;done, go!
;
	PUSH	HL		;save dest
	PUSH	DE		;save source
	LD	C,(IY+2)	;offset into dest
	LD	B,0		;BC = offset
	ADD	HL,BC		;HL => dest record
	EX	DE,HL		;DE => dest record
	LD	C,(IY+0)	;offset into source
	ADD	HL,BC		;HL => source record
	LD	C,(IY+1)	;get field length
	LDIR			;move it in
	POP	DE		;unstack
	POP	HL		;unstack dest
	INC	IY		;go to next entry
	INC	IY
	INC	IY		;3 bytes / entry
	JR	MOVELP		;go next one
;
MOVEND	POP	IY		;restore system pointer
	RET			;data moved!
;
;	get source record from conversion file
;
GETSRC	LD	B,(IY+7)	;get record # source
	LD	H,(IY+8)
	LD	L,(IY+9)
	CALL	COMPSRC		;compute source record
	LD	(IY+13),A	;save record offset
	BIT	7,(IY+1)	;any record in memory?
	JR	Z,GETSRC1	;go if not
	LD	C,(IY+10)	;get current record
	LD	D,(IY+11)
	LD	E,(IY+12)
	CALL	CMPBHL		;compare BHL > CDE
	JR	Z,GETSRC2	;go if in memory
;
GETSRC1	RES	7,(IY+1)	;set NO record
	LD	(IY+10),B	;update record #
	LD	(IY+11),H
	LD	(IY+12),L
	LD	DE,FCBX		;source FCB
	LD	BC,SYSTEM+10	;point to rec #
;
	POSN$			;position to record
	JR	NZ,GETSRC3	;go if error
	READ$			;read record
	JR	NZ,GETSRC3	;go if error
;
GETSRC2	SET	7,(IY+1)	;set record in memory
	XOR	A		;return Z
	RET			;done!
;
GETSRC3	CP	1CH		;end of disk?
	SCF			;C = yes
	RET	Z		;yes, done!
	CP	1DH		;beyond?
	SCF			;C = yes
	RET	Z		;yes, done!
	OR	A		;set NZ, NC
	RET			;return with error
;
;	load record into destination file
;
PUTDES	LD	B,(IY+14)	;get record # adder
	LD	H,(IY+15)
	LD	L,(IY+16)	;BHL = record #
	CALL	COMPSEC		;compute real sector
	LD	(IY+20),A	;save offset
	CALL	INCBHL		;inc for index sect
	LD	(IY+17),B	;update record #
	LD	(IY+18),H
	LD	(IY+19),L
	CALL	MOVREC		;move record to buffer
	LD	A,(IY+20)	;get byte offset
	OR	A		;offset = 0?
	RET	Z		;yes, don't write yet!
;
	LD	A,(IY+1)	;get file type
	AND	7		;low 3 bits
	DEC	A		;special delivery?
	CALL	Z,ADJSD		;yes, remove 5F's
;
	LD	BC,SYSTEM+17	;point to rec #
	LD	DE,FCBA		;adder FCB
;
	POSN$			;position to record
	JR	Z,PUTDES3	;go if no error
	CP	1CH		;end of file?
	JR	Z,PUTDES3	;go if yes
	CP	1DH		;beyond file?
	RET	NZ		;go if neither
;
PUTDES3	WRITE$			;write the record
	RET			;return with status
;
;	remove 5F's from special delivery records
;
ADJSD	LD	HL,BUFFA	;adder I/O buffer
	CALL	ADJSD1		;adjust record
	LD	HL,BUFFA+128	;second record
;
ADJSD1	LD	B,125		;data count
ADJSD2	LD	A,(HL)		;get a char
	CP	5FH		;gap?
	JR	NZ,ADJSD3	;go if not
	LD	(HL),' '	;change to space
ADJSD3	INC	HL		;bump pointer
	DJNZ	ADJSD2		;go for length
	RET			;done!
;
	SUBTTL	'<maildc/asm - text/tables>'
;
	PAGE
;
MSGC1	DEFB	SETCUR
	DEFB	12,00
	DEFB	EOF
;
	DEFM	'(1) Postman(tm)'
	DEFB	SETCUR
	DEFB	12,COLS/2
	DEFM	'(4) R/S MailList(tm) Expanded'
	DEFB	CR
;
	DEFM	'(2) Special Delivery(tm)'
	DEFB	SETCUR
	DEFB	13,COLS/2
	DEFM	'(5) R/S MailList(tm) Compressed'
	DEFB	CR
;
	DEFM	'(3) Galactic MailFile(tm)'
	DEFB	SETCUR
	DEFB	14,COLS/2
	DEFM	'(6) PowerMAIL I(tm)'
	DEFB	CR
;
	DEFM	'Choice ? '
	DEFB	ETX
;
MSGCC	DEFB	SETCUR
	DEFB	12,00
	DEFB	EOF
	DEFM	'Cannot Convert, Adder File '
	DEFM	'NOT AVAILABLE, (KEY):'
	DEFB	ETX
;
MSGC2	DEFB	SETCUR
	DEFB	12,00
	DEFB	EOF
;
	DEFB	CR
	DEFM	'Filespec to Convert ? '
	DEFB	ETX
;
MSGC4	DEFB	SETCUR
	DEFB	14,00
	DEFB	EOF
	DEFM	'Converting File - '
	DEFB	ETX
;
MSGC5	DEFM	'Completed, (KEY):'
	DEFB	ETX
;
MSGC6	DEFB	SETCUR
	DEFB	14,00
	DEFB	EOF
MSGC6A	DEFM	'xxxxxxxx Records Converted, (KEY):'
	DEFB	ETX
;
;	lookup table for conversions
;
TABLEC1	DEFW	POSTDAT		;postman
	DEFW	SPECDAT		;special delivery
	DEFW	GALADAT		;galactic mailfile
	DEFW	RSMEDAT		;R/S maillist expanded
	DEFW	RSMCDAT		;R/S maillist compressed
	DEFW	PMAIDAT		;pmail I
;
;	specific conversion table
;
POSTDAT	DEFB	000,010,113	;code => data 2 (+2)
	DEFB	010,015,000	;last name (+0)
	DEFB	025,010,015	;first name (-5)
	DEFB	040,020,025	;company (-6)
	DEFB	066,020,045	;address=>addr1 (-6)
	DEFB	086,006,065	;address=>addr2 (+4)
	DEFB	092,015,075	;city (+0)
	DEFB	107,005,090	;state (+3)
	DEFB	112,009,098	;zip (+1)
	DEFB	121,002,123	;data1=>data2 (+0)
	DEFB	123,005,108	;data 2 => data 1
	DEFB	-1,-1,-1	;terminator
;
SPECDAT	DEFB	000,015,000	;name15 => last (+0)
	DEFB	015,010,015	;name10 => first (+0)
	DEFB	025,020,025	;company (-5)
	DEFB	050,020,045	;address20 = addr 1
	DEFB	070,005,065	;address5 => addr 2
	DEFB	075,015,075	;city => city (-2)
	DEFB	093,002,090	;state => state (+5)
	DEFB	095,005,098	;zip => zip (+5)
	DEFB	100,012,113	;data 1 => data 2 (-2)
	DEFB	114,005,108	;data 2 => data 1 (-9)
	DEFB	-1,-1,-1	;terminator
;
GALADAT	DEFB	000,015,000	;name 1 => last
	DEFB	015,010,015	;name 1 = first (-2)
	DEFB	027,020,025	;name 2 => company (-7)
	DEFB	054,020,045	;address20 => addr 1
	DEFB	074,007,065	;address7 => addr 2 (-2)
	DEFB	081,015,075	;city => city (+0)
	DEFB	096,003,090	;state => state (+5)
	DEFB	099,010,098	;zip => zip (-1)
	DEFB	122,006,113	;code => data 2 (+6)
	DEFB	-1,-1,-1	;terminator
;
RSMEDAT	DEFB	018,010,015	;first => first (-3)
	DEFB	000,015,000	;last => last (-1)
	DEFB	034,020,025	;company => company (+0)
	DEFB	054,020,045	;address => addr 1 (+0)
	DEFB	074,015,075	;city => city (-5)
	DEFB	094,002,090	;state => state (+5)
	DEFB	096,009,098	;zip => zip (+1)
	DEFB	107,012,113	;remarks => data 2 (-8)
	DEFB	-1,-1,-1
;
RSMCDAT	DEFB	014,009,015	;first => first (+1)
	DEFB	000,014,000	;last => last (+1)
	DEFB	023,017,025	;company => company (+3)
	DEFB	040,018,045	;address => addr 1 (+2)
	DEFB	058,014,075	;city => city (+1)
	DEFB	072,002,090	;state => state (+6)
	DEFB	074,009,098	;zip => zip (+1)
	DEFB	-1,-1,-1	;terminator
;
PMAIDAT	DEFB	000,015,000	;last => last (+0)
	DEFB	015,010,015	;first => first (-2)
	DEFB	027,018,025	;company => company (+2)
	DEFB	045,020,045	;addr1 => addr1 (-4)
	DEFB	069,010,065	;addr2 => addr2 (+0)
	DEFB	079,015,075	;city => city (-1)
	DEFB	095,008,090	;state => state (+0)
	DEFB	103,010,098	;zip => zip (+0)
	DEFB	113,004,108	;data1 => data1 (+1)
	DEFB	117,008,113	;data2 => data2 (+4)
	DEFB	125,003,125	;flags
	DEFB	-1,-1,-1	;terminator
;
