	title	'COMBINE.ASM	12/20/79'
	page	0

;12/10/78 BY Ward Christensen
;Modified by Bob Van Valzah & Steve Ness on 1/9/78 to allow
;source files on any drive and remove comments preceded by blanks.
;
;Modified by Steve Ness on 12/20/79 to allow filetypes on source files.
;
;Used to combine multiple small programs into one large assembly file.
;
;command format:
;
;	COMBINE output=input1,input2....
;
;The input files may have a: or b: specified.
;The output file may have A: or B: specified.

TEST	EQU	0
K	EQU	1024	;1K
BLKSIZE	EQU	12*K	;OUTPUT FILE BLOCKSIZE
;
;(FROM EQU7.LIB...)
MF	SET	0	;SHOW MOVE NOT REQUESTED
CF	SET	0	;SHOW COMP NOT REQUESTED
;
;DEFINE SOME MACROS TO MAKE THINGS EASIER
;
;DEFINE DATA MOVE MACRO
;
MOVE	MACRO	?F,?T,?L,?I
	IF	NOT NUL ?F
	LXI	H,?F
	ENDIF
	IF	NOT NUL ?T
	LXI	D,?T
	ENDIF
	IF	NOT NUL ?L
	LXI	B,?L
	ENDIF
	IF	NOT NUL ?I
	LOCAL	?B,?Z
	CALL	?Z
?B	DB	?I
?Z	POP	H	;GET TO
	LXI	B,?Z-?B
	ENDIF
	CALL	MOVER
MF	SET	-1	;;SHOW EXPANSION
	ENDM
;COMPARE MACRO
COMP	MACRO	?F,?T,?L,?I
	IF	NOT NUL ?F
	LXI	H,?F
	ENDIF
	IF	NOT NUL ?T
	LXI	D,?T
	ENDIF
	IF	NOT NUL ?L
	LXI	B,?L
	ENDIF
	IF	NOT NUL ?I
	LOCAL	?B,?Z
	CALL	?Z
?B	DB	?I
?Z	POP	D	;GET TO
	LXI	B,?Z-?B
	ENDIF
	CALL	COMPR
CF	SET	-1	;;SHOW EXPANSION
	ENDM
;
;DEFINE CP/M MACRO - CPM FNC,PARM
;
CPM	MACRO	?F,?P
	PUSH	B
	PUSH	D
	PUSH	H
	IF	NOT NUL ?F
	MVI	C,?F
	ENDIF
	IF	NOT NUL ?P
	LXI	D,?P
	ENDIF
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	ENDM
;
	ORG	100H
;INIT LOCAL STACK
;
	LXI	H,0
	DAD	SP
	SHLD	STACK
	LXI	SP,STACK
;
;START OF PROGRAM EXECUTION
;
;MOVE THE COMMAND BUFFER
	MOVE	80H,HOLD,80H ;FROM,TO,LENGTH
;ERASE THE OUTPUT FILE
	IF	NOT TEST
	CPM	ERASE,FCB
	CPM	MAKE,FCB
	INR	A
	JZ	NOROOM
	ENDIF
;POSITION TO FIRST NAME TO COPY (FOLLOWS =)
	LXI	H,HOLD
SKIPEQ	INX	H
	MOV	A,M
	CPI	'='
	JNZ	SKIPEQ
	SHLD	NAMEADD	;SAVE POINTER
	CALL	NEXTFL	;PRIME THINGS
LOOP	CALL	WRBYTE
	CALL	RDBYTE
	JNC	LOOP
;DONE -
	MVI	A,1AH
	CALL	WRBYTE
	LHLD	WRCOUNT
	LXI	D,128
	DAD	D	;FORCE LAST SECTOR
	SHLD	WRCOUNT	;..WRITE
	CALL	WRBUFS	;WRITE THE BUFFER
	CPM	CLOSE,FCB
	INR	A
	JNZ	EXIT
	CALL	ERXIT
	DB	'++CLOSE ERROR++$'
;
;WRITE BYTE TO OUTPUT FILE
;
WRBYTE	LHLD	WRBUFAD
	MOV	M,A
	INX	H
	SHLD	WRBUFAD
;BUMP COUNT
	LHLD	WRCOUNT
	INX	H
	SHLD	WRCOUNT
;SEE IF TIME TO WRITE BUFFER
	DAD	H	;H=# SECTORS
	MOV	A,H
	CPI	BLKSIZE/128
	RNZ
;TIME TO WRITE THE OUTPUT BUFFER
;
WRBUFS	LXI	H,WRBUFF
	SHLD	WRBUFAD
	XCHG
	LHLD	WRCOUNT
	DAD	H	;H=# SECTORS
	MOV	B,H	;SAVE SECTOR COUNT
	MOV	A,B
	ORA	A	;0 SECTORS? (POSS AT EOF)
	JNZ	WRBFLP
	INR	B	;FUDGE IN PARTIAL SECTOR
WRBFLP	CPM	SETDMA
	CPM	WRITE,FCB
	ORA	A
	JNZ	WRERR
	LXI	H,80H
	DAD	D
	XCHG
	DCR	B
	JNZ	WRBFLP
	LXI	H,0
	SHLD	WRCOUNT
	RET
;
WRERR	CALL	ERXIT
	DB	'++WRITE ERROR++$'
;
;READ BYTE FROM INPUT FILE
;
RDBYTE	LHLD	RDBUFAD
	LDA	RDCOUNT	;GET CHAR COUNT
	ORA	A	;TIME TO READ?
	JP	NOREAD
;HAVE TO READ
	CPM	SETDMA,RDBUFF
	CPM	READ,RDFCB
	ORA	A
	JNZ	RDERR
	CPM	SETDMA,80H
	LXI	H,RDBUFF
	MVI	A,0
NOREAD	INR	A
	STA	RDCOUNT	;SAVE CHAR COUNT
;CHECK FOR NEW LINE OR TAB, TO DELETE COMMENTS
	LDA	PREV
	CPI	9
	JZ	TESTCOM
	CPI	' '
	JZ	TESTCOM
	CPI	0AH	;LF?
	JZ	TESTCM1
NOCOM	MOV	A,M	;GET CHAR
	INX	H
	SHLD	RDBUFAD
	CPI	'Z'-40H	;EOF?
	JZ	NEXTFL
	STA	PREV	;SAVE FOR COMMENTS TEST
	ORA	A	;CARRY OFF SHOWN NOT EOF
	RET
;
;TEST FOR COMMENT
TESTCOM	MOV	A,M
	CPI	';'
	JNZ	NOCOM
;GOT COMMENT, SKIP IT
	STA	PREV
	INX	H
	SHLD	RDBUFAD
SKIPCOM	CALL	RDBYTE
	CPI	0DH
	JNZ	SKIPCOM
	STA	PREV
	RET
TESTCM1	MOV	A,M
	CPI	';'
	JNZ	NOCOM
	STA	PREV
	INX	H
	SHLD	RDBUFAD
;DELETE ENTIRE LINE
DELINE	CALL	RDBYTE
	CPI	0AH
	JNZ	DELINE
	JMP	RDBYTE	;GET, RET NEXT CHAR
;GOT EOF - GET NEXT FILE
RDERR	CALL	ERXIT
	DB	'++READ ERROR++$'
NEXTFL	LHLD	NAMEADD	;GET NAME POINTER
	MOV	A,M	;GET DELIMITER
	ORA	A
	STC
	RZ		;RET IF ALL DONE
	INX	H	;SKIP DELIMITER
	LXI	D,RDFCB ;POINT TO NAME
	xra	a	;prepare to use default drive
	stax	d
	inx	d
	PUSH	D
;BLANK THE FCB
	MVI	A,' '
	MVI	B,11
BLANK	STAX	D
	INX	D
	DCR	B
	JNZ	BLANK
	POP	D
	inx	h	;look ahead for colon, indicating drive
	mov	a,m
	dcx	h	;backup j.i.c. not there
	cpi	':'	;was a drive specified?
	jnz	moven	;nope - just scan off file name
	mov	a,m	;yup - insert drive name into fcb
	sui	'A'-1
	sta	rdfcb
	inx	h	;move source pointer over drive spec.
	inx	h
MOVEN	MOV	A,M
	CPI	','
	JZ	MOVED
	cpi	'.'
	jz	movft
	ORA	A	;ZERO @ END?
	JZ	MOVED
	STAX	D
	INX	H
	INX	D
	JMP	MOVEN
movft	inx	h
	lxi	d,rdfcb+9	;address filetype of read block
	jmp	moven
;ALL DONE MOVING
MOVED	SHLD	NAMEADD	;SAVE NAME LIST ADDR
	XRA	A
	STA	RDEXT	;ZERO EXTENT
	STA	RDRNO	;ZERO RECORD #
	CPM	SETDMA,RDBUFF
	CPM	OPEN,RDFCB
	INR	A
	JZ	OPENERR
	MVI	A,80H	;SHOW TIME TO READ
	STA	RDCOUNT
	CPM	SETDMA,80H
	JMP	RDBYTE
OPENERR	LXI	H,RDFCB+1
	MVI	B,11
NAMELP	MOV	A,M
	CALL	TYPE
	INX	H
	DCR	B
	JNZ	NAMELP
	CALL	ERXIT
	DB	': ++OPEN FAILED++$'
NOROOM	CALL	ERXIT
	DB	'++NO ROOM ON OUTPUT DISK$'
;
TYPE	MOV	E,A
	CPM	WRCON
	RET
;
;FOLLOWING FROM 'EQU7.LIB'---->
;
;MOVE, COMPARE SUBROUTINES
;
	IF	MF	;MACRO EXPANSION FLAG SET?
MOVER	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVER
	RET
	ENDIF
;
;
	IF	CF	;MACRO EXPANSION FLAG SET?
COMPR	LDAX	D
	CMP	M
	RNZ
	INX	D
	INX	H
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	COMPR
	RET
	ENDIF
;EXIT WITH ERROR MESSAGE
MSGEXIT	EQU	$	;EXIT W/"INFORMATIONAL" MSG
ERXIT	POP	D	;GET MSG
	MVI	C,PRINT
	CALL	BDOS
;EXIT, RESTORING STACK AND RETURN
EXIT	LHLD	STACK
	SPHL
	RET		;TO CCP
PREV	DB	0AH	;PREV CHAR FOR COMMENTS TEST
WRBUFAD	DW	WRBUFF	;OUTPUT BUFFER ADDR
WRCOUNT	DW	0	;BYTE COUNTER
RDBUFAD	DW	RDBUFF
RDDRV	DB	0	;DRIVE NAME TO READ FROM
RDFCB	DB	0,'           '
RDEXT	DB	0
	DS	19
RDRNO	DB	0
RDCOUNT	DB	80H	;CHARACTER COUNT IN BUFF
	DS	40H	;STACK AREA
STACK	DS	2
;POINTER TO LIST OF FILENAMES
NAMEADD	DS	2
;COPY OF INPUT COMMAND BUFFER (FROM 80H)
HOLD	DS	128
;OUTPUT DISK BUFFER
	ORG	($+255) AND 0FF00H ;TO PAGE
RDBUFF	DS	128
WRBUFF	DS	BLKSIZE
;BDOS/CBIOS EQUATES (VERSION 7)	
RDCON	EQU	1
WRCON	EQU	2
PRINT	EQU	9
CONST	EQU	11
OPEN	EQU	15
CLOSE	EQU	16
SRCHF	EQU	17
SRCHN	EQU	18
ERASE	EQU	19
READ	EQU	20
WRITE	EQU	21
MAKE	EQU	22
REN	EQU	23
SETDMA	EQU	26
BDOS	EQU	5
FCB	EQU	5CH 
FCB2	EQU	6CH
FCBEXT	EQU	FCB+12
FCBRNO	EQU	FCB+32
