                             .XLIST

                      .INSERT  SWITCHES.DEF

;    **************************************************
;    **************************************************
;    **************************************************



;                       DEBUGGING SWITCH:
;                       --------- ------

	                 DEBUG  ==  OFF


;                       LISTING OPTIONS:
;                       ------- -------

	              DEFINITIONS  ==  OFF
	              MACROS       ==  OFF
                      MESSAGES     ==  OFF
	              LIBRARY      ==  OFF
	              SYMBOLS      ==  OFF

                             .XLIST


;                      ASSEMBLY CONTROLS:
;                      -------- --------

                              .PABS

                              .PHEX

                              .LADDR

                              .RADIX  16

                   .IFE   MACROS - OFF, .SALL

                   .IFE  SYMBOLS - OFF, .XSYM



                              .LIST

;    **************************************************
;    **************************************************



                              .LCTL

;                         ************
	.TITLE           "PRINTLAW.COM"
;                         ************

                              .XCTL


;                       Version:    1.01a

;                 First Written:    02/02/90

;                 Last Modified:    07/04/90


                  .IFE  DEBUG - ON, .XLIST


;                          **********
;                          LABEL DATA:
;                          **********



                      VERSION	=       '1'
                      MODIF	=	'01'
                      CHANGE	=	'a'

                      MONTH	=       '07'
                      DAY	=	'04'
                      YEAR	=	'90'



;                        ***************
;	                 ASSEMBLY OPTION:
;                        ***************


		      SPOOLER      =    ON

                      STANDALONE   =    SPOOLER - OFF

;                         * END OPTION *



;                            ******
;                            SAMPLE
;                            DIALOG:
;                            ******



;	A>PRINTLAW  [LAWFILE.PRN]  [/pJ-K]  [/cN]  [/r]  [/u]
;
;
;		PRINTLAW Utility       Version:  1.00x
;
;                     Add Line Numbers To Legal Documents
;                               During Printout
;
;                    Implement Underlining On WANG Printer
;
;
;               FILE TO PRINT?   LAWBRIEF[.PRN]
;
;
;                            PRINTING   "LAWBRIEF"
;
;                      COPY #:   1           PAGE #:   3
;
;
;               DONE PRINTING
;
;		EXIT TO CP/M
;
;
;	A>



;                            *******
;                            HISTORY:
Š;                            *******



;       02/02/90:	First version written to number
;			legal documents automatically,
;			using .PRN file inputs 
;			generated from WordStar.

;			Operate on .PRN filetype only,
;			to guard against blunders.

;			Takes advantage of the filter
;			to implement underlining on the
;			Wang printer, by trapping  ^S
;			outputs from WordStar, and
;			using them to toggle a switch
;			which turns "Bit 8" on/off.

;			Added an "R" option to turn
;			the right-hand vertical rule
;			feature on.  This speeds up
;			printing under the default
;			condition ("off"), because
;			blank lines don't have to be 
;			padded out to the right-hand
;			edge of the page.

;	04/23/90:	When the Master disk was 
;			revived, we added an assembly
;			switch ("SPOOLER") to disable
;			auto-patching of the station
;			BIOS, which previously had to
;			be "fixed" to permit Bit-8 
;			(the Wang underline flag) to
;			get through to the printer.
;			When the spooler is used, this
;			patching has to be done at the
;			Master instead, by running a
;			special "UNDRLINE" utility
;			which enables underscoring.

;                                  HOWEVER:
;			Turned out that underline wire
;			in the printhead was "sticky",
;			causing the ribbon to hang-up
;			on long underscores.  So
;			added a "U" option to enable
;			underlining. Default setting
;			of this switch was formerly 
;			"off".  Tentatively changed
;			the default setting to "on"
;			in early April, after the
;			printhead was overhauled.
;			Seems to be OK, but left the
;			option code in place, just
;			in case  .  .  .

;			Later on, can add options 
;			to print multiple copies, 
;			and selected pages from file.
;			It may then become necessary
;			to limit the length of input
;			in terms of physical pages
;			(e.g., 99?).  The "hooks"
;			for this are all in place.
;			Need only to work out 
;			the interface procedures.

;	07/04/90:	BUG.  Skips every 8th page in
;			printing out.  Added JZ after
;			JC in "PAGE.UP" subroutine,
;			to skip when ACC <= 0 instead
;			of ACC < 0.


;    **************************************************
;    **************************************************



;                            *****
;                            NOTES:
;                            *****



;	(1)	Page framing in the legal source
;		document MUST be set as follows,
;		to ensure proper alignment and
;		avoid interference between the
;		merging streams:
;
;			.MT	6
;			.MB	4
;			.PO	15
;                    MARGINS:  1 - 64
                              .PAGE
                  .SBTTL  "SYMBOLIC CONSTANTS"

;    **************************************************
;    **************************************************



;                           *********
;                            SYMBOLIC
;                           CONSTANTS:
;                           *********



                       .INSERT  CPM.DEF


                       .INSERT  ASCII.DEF


                       .INSERT  SWITCHES.DEF


                 .IFE  DEFINITIONS - ON,  .LIST


;                      MAPPING CONSTANTS:
;                      ------- ---------


Š		LOAD.POINT	==	TPA

		STACK.SIZE	==	20 ; (words)


;                   SPECIAL PROGRAM CONSTANTS:
;                   ------- ------- ---------


		PRINTER.PATCH	==	    0F3A7

		BUFFER.SIZE	==	0D800 ; (54K)

		MAX.FILE.SIZE	==	01B0 ; records


;                       GENERAL UTILITY:
;                       ------- -------


		BYTE.SIZE	==	1  ; bytes

		WORD.SIZE	==	2  ; bytes
                              .LIST
                              .PAGE
                    .SBTTL  "ROOT PROCEDURE"

;    **************************************************
;    **************************************************



;                          *********
;                          PROCEDURE:
;                          *********



		       .LOC   LOAD.POINT


			     FIRST:

                          JMP	START


                    .IFE  DEBUG - ON, .XLIST


;                            LABEL:
;                            -----


..NAME:
		.ASCII	'PRINTLAW.COM'
		.BYTE	END.MESSAGE

VERS.NUMBER:
		.ASCII	'Version:  '
		.BYTE	VERSION
		.BYTE	'.'
		.BYTE	MODIF / 100
		.BYTE	MODIF @ 100
		.BYTE	CHANGE
		.BYTE	END.MESSAGE

..DATE:
		.ASCII	'Date:  '
		.BYTE	MONTH / 100
		.BYTE	MONTH @ 100
		.BYTE	'/'
		.BYTE	DAY / 100
		.BYTE	DAY @ 100
		.BYTE	'/'
		.BYTE	YEAR / 100
Š		.BYTE	YEAR @ 100
		.BYTE	END.MESSAGE


                              .LIST


START:
	LXI	SP, TOP.STACK

	LXI	H, PAGE.MAP
	LXI	B, 8
	MVI	A, SET
	CALL	FILL

MAIN:
	LXI	D, HELLO
	CALL	FLASH
	CALL	SPC5
	LXI	D, VERS.NUMBER
	CALL	FLASH
	CALL	CRLF
	CALL	LFEED


	LDA	COM.TAIL.LENGTH
	LXI	H, COMMAND.TAIL
	CALL	MARK.END
	CALL	PARSE.LINE

	LDA	ARGC
	CPI	ZERO
	JRNZ	..ARGUMENTS

	LXI	D, BLURB
	CALL	FLASH
	JMPR	PROMPT.LINE

..ARGUMENTS:

	CPI	4
	JC	OPTIONS.CHECK

TROUBLE:

;		BAIL OUT OF THIS, IF
;		COMMAND-TAIL IS A DUD:

	LXI	D, COMPLAIN
	CALL	FLASH

PROMPT.LINE:

	LXI	D, NAME.PROMPT
	CALL	FLASH

	MVI	A, 10
	STA	MAX.LINE
	CALL	GET.LINE
	CALL	CRLF
	CALL	LFEED

;		CHECK FOR INPUT OVERFLOW:

	LDA	CHAR.COUNT
	LXI	H, MAX.LINE
	CMP	M
	JRZ	TROUBLE

;		PARSE THE INPUT STRING:

	LXI	H, LINE.IN
	CALL	MARK.END
	CALL	PARSE.LINE

	LDA	ARGC
	CPI	4
	JNC	TROUBLE

OPTIONS.CHECK:

;		LATER ON WILL HAVE TO SET THIS
;		TO 1 OR TO 2, DEPENDING ON WHETHER
;		FIRST ARGUMENT IS A SINGLE-
;		CHARACTER NUMERIC ('0' THRU '9'),
;		INDICATING NUMBER OF COPIES REQUESTED:

	MVI	A, 1
	STA	ARG.POINTER

..NEXT.ARG:

	LDA	ARGC
	LXI	H, ARG.POINTER
	CMP	M
	JRZ	..SKIP

;		GET A POINTER TO THE ARGUMENT IN "HL":

	MOV	A, M		; ARG.POINTER
	INR	M
	MVI	B, WORD.SIZE
	LXI	H, ARGV
	CALL	SUBSCRIPT
	CALL	INDIRECT
	CALL	UP.CASE.STRING

;		THEN LOOK FOR MATCH-UPS:

..R.CHECK:

	LXI	D, ..R.OPTION
	CALL	STRCMP
	JRNZ	..U.CHECK

;		SET FOR RIGHT-MARGIN RULING
;		IF REQUESTED:

	MVI	A, ON
	STA	RULER.SWITCH
	JMPR	..NEXT.ARG

..U.CHECK:

	LXI	D, ..U.OPTION
	CALL	STRCMP
	JRNZ	TROUBLE

	MVI	A, OFF
	STA	DISABLE.UNDERLINE
	JMPR	..NEXT.ARG

..R.OPTION:

	.ASCIZ	'R'

..U.OPTION:

	.ASCIZ	'U'

..SKIP:

;		END OF OPTION SWITCHES

DISSECT.INPUT.STRING:

	CALL	ANALYZE.FILESPEC
	CPI	OK
	JRNZ	TROUBLE

SETUP.FCB:

;		SAVE THE FILENAME POINTER
;		PASSED BY "ANALYZE.FILESPEC":

	PUSH	H

;		CREATE THE DEFAULT FCB:

	CALL	PREPARE.FCB

;		MOVE INPUT FILENAME INTO POSITION
;		IN THE "ACKNOWLEDGE" MESSAGE:

	POP	H
	CALL	INDIRECT
	LXI	D, LAWFILE
	CALL	STRCPY

;		ONLY ".PRN" TYPES WILL BE ACCEPTED:

	LXI	H, LAWFILE
	LXI	D, PRN.TYPE
	CALL	STRCAT

	LXI	H, LAWFILE
	CALL	UP.CASE.STRING

REJECT.ANY.WILDCARDS:

	LXI	H, FILENAME
	MVI	C, 0B

..SCAN:
	MOV	A, M
	CPI	'*'
	JRZ	..TROUBLE
	CPI	'?'
	JRZ	..TROUBLE

	INX	H
	DCR	C
	JRNZ	..SCAN

	JMPR	PRN.FILES.ONLY

..TROUBLE:

	LXI	D, NO.WILDCARDS
	CALL	FLASH
	JMP	PROMPT.LINE

PRN.FILES.ONLY:

	LXI	H, PRN.TYPE + 1
	LXI	D, FILETYPE
	LDAX	D
	CPI	SPACE
	JRNZ	TYPE.CHECK

;		LOOK FOR A ".PRN" FILE, IF
;		NO FILETYPE IS SPECIFIED:

	LXI	B, 3
	CALL	MOVE
	JMPR	OPEN.PRINT.FILE

PRN.TYPE:

	.ASCIZ	'.PRN'

;		OTHERWISE, MAKE SURE THAT THE
;		INPUT FILE IS TYPE ".PRN":

TYPE.CHECK:

	XCHG
	LDAX	D
	CPI	NULL
	JRZ	OPEN.PRINT.FILE

	CMP	M
	JRZ	..OK.SO.FAR

	LXI	D, TYPE.SQUAWK
	CALL	FLASH
	JMP	PROMPT.LINE

..OK.SO.FAR:

	INX	D
	INX	H
	JMPR	TYPE.CHECK

OPEN.PRINT.FILE:

	CALL	OPEN.FILE
	CPI	OK
	JRZ	SIZE.CHECK

	LXI	D, BUM.FILENAME
	CALL	FLASH
	JMP	PROMPT.LINE

;		CHECK THE GROSS NUMBER OF PAGES
;		AGAINST THE PARAMETRIC LIMIT:

SIZE.CHECK:

	CALL	SIZE.FILE

	LDA	FILE.LENGTH + 2
	ORA	A
	JRNZ	..SIZ1

	LHLD	FILE.LENGTH
	SHLD	SIZE.SAVE
	LXI	D, MAX.FILE.SIZE + 1
	STC
	CMC
	DSBC	D
	JC	BEGIN

;		    SIZE-ERROR PROCEDURE:
;		FOR NOW, WE'LL TAKE ANYTHING!

..SIZ1:

;		ACKNOWLEDGE THE COMMAND:

BEGIN:

	LXI	D, ACKNOWLEDGE
	CALL	FLASH
	MVI	A, '"'
	CALL	PUTCHAR
	CALL	CRLF
	CALL	LFEED


			.IFE	STANDALONE, [

;		       DISABLE THE BIT-8 MASK IN
;		        THE BIOS PRINTER PATCH:
;
;		     ( RE-ENABLED PRIOR TO EXIT )

	MVI	A, 0FFH
	STA	PRINTER.PATCH               ]


;		RETURN POINT FOR MULTIPLE COPIES:

RE.PRINT:

	LDA	COPY.NO
	LXI	H, COPIES.REQUESTED
	CMP	M
	JZ	NORM.EXIT

	INR	A
	STA	COPY.NO

	CALL	D.CONVERT
	MOV	A, B
	STA	COPY

	MVI	A, SPACE
	STA	PAGE
	STA	PAGE + 1

	CALL	CRET
	LXI	D, STATUS
	CALL	FLASH

	MVI	A, ON
	STA	PRINTING.SWITCH

	MVI	A, 1
	STA	PAGE.NO
	STA	LINE.NO
	STA	COLUMN.NO

	MVI	A, SET
	STA	CR.FLAG
	STA	LF.FLAG

	MVI	A, OFF
	STA	UNDERLINE

;		ZERO THE FILE'S RECORD-POINTER:

	MVI	A, ZERO
	STA	SEQ.POINTER

	LXI	H, END.BUFFER
	SHLD	BUFF.POINTER

DO.PRINTING:

;		SEE IF THE BUFFER IS EXHAUSTED,
;		AND RE-LOAD IT IF NECESSARY:

	LHLD	BUFF.POINTER
	LXI	D, END.BUFFER
	STC
	CMC
	DSBC	D
	JRNZ	END.OF.FILE.CHECK

	CALL	LOAD.THE.BUFFER

END.OF.FILE.CHECK:

	LHLD	BUFF.POINTER
	MOV	A, M
	CPI	EOF
	JZ	RE.PRINT

;		CHECK FOR THE "BREAK" KEY:

BREAK.CHECK:

	CALL	IF.KEY.GET
	CPI	BREAK
	JZ	ABEND

;		TEST FOR BEGINNING OF A NEW LINE:

	LDA	CR.FLAG
	LXI	H, LF.FLAG
	ANA	M
	CPI	CLEAR
	JZ	MAIN.FILE

;		RE-CHECK THE PAGE SELECTION MECHANISM
;		ON THE FIRST LINE OF EACH NEW PAGE:

	LDA	LINE.NO
	CPI	1

	CZ	PAGE.UP   ; UPDATE THE SELECTOR SWITCH

;		IF THE CURRENT PAGE IS SELECTED,
;		RESUME PRINTING, WITH A MERGE:

	LDA	PRINTING.SWITCH
	CPI	ON
	JRZ	MERGE.STREAM

;		OTHERWISE DUMP INPUT CHARACTERS
;		UNTIL WE COME TO A PAGE
;		THAT IS SELECTED:

	LHLD	BUFF.POINTER
	MOV	A, M
	INX	H
	SHLD	BUFF.POINTER

	ANI	7FH

;		KEEP TRACK OF THE PRINT TOGGLE,
;		IN CASE AN UNDERSCORE
;		STRADDLES TWO PAGES:

..PR.TOGGLE:

	CPI	''
	JRNZ	..LF.CHAR

;		SEE IF UNDERLINING IS REQUESTED:

	LDA	DISABLE.UNDERLINE
	CPI	SET
	JZ	DO.PRINTING

;		IF SO, TOGGLE THE SWITCH:

	LDA	UNDERLINE
	CMA
	STA	UNDERLINE

	JMP	DO.PRINTING

;		PROCESS LINE-FEEDS:

..LF.CHAR:

	CPI	LF
	JRNZ	DO.PRINTING

	LDA	LINE.NO
	INR	A
	STA	LINE.NO

	CPI	^D66 + 1
	JC	DO.PRINTING

;		RESET THE PAGE ON LAST LINE:

	MVI	A, 1
	STA	LINE.NO

	LDA	PAGE.NO
	INR	A
	STA	PAGE.NO

	JMP	DO.PRINTING

MERGE.STREAM:

;		FIRST OF ALL UPDATE THE PAGE DISPLAY,
;		BEFORE PRINTING THE INITIAL LINE 
;		OF A NEW PAGE:

	LDA	LINE.NO
	CPI	1
	JRNZ	..SKIP

	LDA	PAGE.NO
	CALL	D.CONVERT
	STA	PAGE
	MOV	A, B
	STA	PAGE + 1

	MVI	A, BACKSPACE
	CALL	PUTCHAR
	CALL	PUTCHAR
	CALL	PUTCHAR
	CALL	PUTCHAR

	LXI	D, PAGE
	CALL	FLASH

..SKIP:

	MVI	A, SPACE
	STA	..LINE.NUMBER
	STA	..LINE.NUMBER + 1

;		NO LINE NUMBERS IN THE TOP
;		AND BOTTOM MARGINS:

	LDA	LINE.NO
	CPI	^D7
	JC	..IDLE

	CPI	^D62
	JNC	..IDLE

;                      THE MAGIC ALGORITHM!
;                    FOR 28-LINE BRIEF PAPER
;		       # = LINE.NO / 2 - 2

;		SKIP NUMBERS ON ALTERNATE LINES:

	SRLR	A
	JNC	..IDLE

	SUI	2

;		ACCUMULATOR NOW HAS THE NUMBER OF
;		THE BRIEF LINE ABOUT TO BE PRINTED

	CALL	D.CONVERT
	STA	..LINE.NUMBER
	MOV	A, B
	STA	..LINE.NUMBER + 1

..IDLE:

	LXI	D, ..MARGIN
	CALL	PRINT

..CLEAR.FLAGS:

	MVI	A, CLEAR
	STA	CR.FLAG
	STA	LF.FLAG

	MVI	A, ^D15
	STA	COLUMN.NO

;		ADJUST THE BUFFER POINTER, IF THIS
;		LINE IS NOT "NULL".  OTHERWISE, LET
;		THE PROGRAM SIMPLY PAD OUT TO THE
;		END OF THE LINE, WHEN THE NEXT "CR"
;		IS ENCOUNTERED:

	LHLD	BUFF.POINTER
	MOV	A, M
	CPI	SPACE
	JNZ	DO.PRINTING

	LXI	D, ^D15
	DAD	D
	SHLD	BUFF.POINTER

;			  DANGER!
;		MAKE SURE WE HAVEN'T SKIDDED
;		PAST THE END OF THE BUFFER:

	LXI	D, END.BUFFER
	STC
	CMC
	DSBC	D
	JC	DO.PRINTING

	PUSH	H
	CALL	LOAD.THE.BUFFER
	POP	D
	DAD	D
	SHLD	BUFF.POINTER

	JMP	DO.PRINTING

..MARGIN:
	.ASCII	'         '
..LINE.NUMBER:
	.ASCII	'  '
	.ASCII	'  | '
	.BYTE	END.MESSAGE

MAIN.FILE:

;		DO THE NEXT FILE BYTE:

	LHLD	BUFF.POINTER
	MOV	A, M
	INX	H
	SHLD	BUFF.POINTER

	ANI	7FH	;  MASK IT, JUST IN CASE

CR.TEST:

	CPI	CR
	JRNZ	LF.TEST

	MVI	A, SET
	STA	CR.FLAG

	LDA	RULER.SWITCH
	CPI	OFF
	JRZ	..SKIP

..PAD.LINE:

	LDA	COLUMN.NO
	CPI	^D80
	JNC	..END.LINE

	MVI	A, SPACE
	CALL	PRCHAR

	LDA	COLUMN.NO
	INR	A
	STA	COLUMN.NO

	JMPR	..PAD.LINE

..END.LINE:

	MVI	A, '|'
	CALL	PRCHAR

..SKIP:

	MVI	A, CR
	CALL	PRCHAR

	MVI	A, 1
	STA	COLUMN.NO

	JMP	DO.PRINTING

LF.TEST:

	CPI	LF
	JRNZ	TOGGLE.TEST

	MVI	A, SET
	STA	LF.FLAG

	LDA	LINE.NO
	INR	A
	STA	LINE.NO

	CPI	^D66 + 1
	JC	..SAME.PAGE

	MVI	A, 1
	STA	LINE.NO

	LDA	PAGE.NO
	INR	A
	STA	PAGE.NO

..SAME.PAGE:

	MVI	A, LF
	CALL	PRCHAR

	JMP	DO.PRINTING

TOGGLE.TEST:

	CPI	''
	JRNZ	OUTPUT.THE.CHARACTER

;		SEE IF UNDERLINING IS REQUESTED:

	LDA	DISABLE.UNDERLINE
	CPI	SET
	JZ	DO.PRINTING

;		IF SO, TOGGLE THE SWITCH:

	LDA	UNDERLINE
	CMA
	STA	UNDERLINE

	JMP	DO.PRINTING

OUTPUT.THE.CHARACTER:

;			UNDERLINING STRATEGY:

;		COLUMN #80 IS ALWAYS A SPACE, AND
;		UNDERSCORING HAS TO BE SUPPRESSED
;		AFTER COLUMN #79, FOR APPEARANCE:

	MOV	B, A
	LDA	COLUMN.NO
	CPI	^D79
	MOV	A, B
	JNC	..SKIP

	MOV	B, A
	LDA	UNDERLINE
	ANI	80H
	ORA	B

..SKIP:

	CALL	PRCHAR

;		UPDATE THE COLUMN COUNTER,
;		FOR "ISPRINTs" ONLY:

	ANI	7FH
	CPI	7FH
	JNC	DO.PRINTING

	CPI	SPACE
	JC	DO.PRINTING

	LDA	COLUMN.NO
	INR	A
	STA	COLUMN.NO

	JMP	DO.PRINTING

NORM.EXIT:

	LXI	D, GOODBYE
	CALL	FLASH
	JMPR	EXIT

ABEND:

	LXI	D, ABORTED
	CALL	FLASH

EXIT:


			.IFE	STANDALONE, [

;		  RE-ENABLE THE BIOS BIT-8 FILTER
;		           PRIOR TO EXIT:

	MVI	A, 7FH
	STA	PRINTER.PATCH               ]


	LXI	D, EXIT.MESSAGE
	CALL	FLASH
	MVI	C, WARM.BOOT
	CALL	SYSTEM
                  .IFE  MESSAGES - OFF,  .XLIST
                    .IFE  DEBUG - OFF,  .LIST
                              .PAGE
                       .SBTTL  "MESSAGES"

;    **************************************************
;    **************************************************



;                           ********
;                           MESSAGES:
;                           ********



HELLO:
	.BYTE	LF, LF
	.ASCII	'     PRINTLAW  Utility '
	.BYTE	END.MESSAGE

BLURB:
	.ASCII	'           Add Line Numbers To Legal Documents'
	.BYTE	CR, LF
	.ASCII	'                     During Printout'
	.BYTE	CR, LF, LF
	.ASCII	'          Implement Underlining On WANG Printer'
	.BYTE	CR, LF, LF, LF
	.BYTE	END.MESSAGE

NAME.PROMPT:
	.ASCII	'     FILE TO PRINT?   '
	.BYTE	END.MESSAGE

COMPLAIN:
	.ASCII	'     WHAT???'
	.BYTE	BEL
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE

NO.WILDCARDS:
	.ASCII	'     AMBIGUOUS FILENAME!'
	.BYTE	BEL
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE

TYPE.SQUAWK:
	.ASCII	'     .PRN FILES ONLY!'
	.BYTE	BEL
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE

BUM.FILENAME:
	.ASCII	'     NO INPUT FILE!'
	.BYTE	BEL
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE

ACKNOWLEDGE:
	.BYTE	LF
	.ASCII	'                 PRINTING:   "'
LAWFILE:
	.ASCII	'            '
	.BYTE	END.MESSAGE

STATUS:
	.ASCII	'           COPY  #:   '
COPY:
	.ASCII	' '
PAGE.STATUS:
	.ASCII	'          PAGE  #:   '
PAGE:
	.ASCII	'    '
	.BYTE	END.MESSAGE

ABORTED:
	.BYTE	CR, LF, LF, LF
	.ASCII	'     PRINT ABORTED'
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE

GOODBYE:
	.BYTE	CR, LF, LF, LF
	.ASCII	'     DONE PRINTING'
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE

EXIT.MESSAGE:
	.ASCII	'     EXIT TO CP/M'
	.BYTE	CR, LF, LF
	.BYTE	END.MESSAGE
                              .LIST
                              .PAGE
            .SBTTL  "PROGRAM FUNCTIONS & SUBROUTINES"

;    **************************************************
;    **************************************************



;                          ***********
;                          SUBROUTINES:
;                          ***********



;                            PROGRAM:
;                            -------


LOAD.THE.BUFFER:

	LXI	H, PRINT.BUFFER
	SHLD	BUFF.POINTER

..CONTINUE:

	LDED	BUFF.POINTER
	LXI	H, 80
Š	DAD	D
	SHLD	BUFF.POINTER

	CALL	SET.DMA

	CALL	SEQ.READ
	CPI	OK
	JRNZ	..STOP

;		BUFFER FULL?

	LHLD	BUFF.POINTER
	LXI	D, END.BUFFER
	STC
	CMC
	DSBC	D
	JRNZ	..CONTINUE

..STOP:

	LXI	H, PRINT.BUFFER
	SHLD	BUFF.POINTER

	RET


PAGE.UP:

	LDA	PAGE.NO
	LXI	H, PAGE.MAP

..BYTES:

	SUI	8
	JC	..BITS
	JZ	..BITS

	INX	H
	JMPR	..BYTES

..BITS:

	ADI	8
	MOV	B, M

..SHIFT:

	DCR	A
	JRZ	..RESET.PRINT.SWITCH

	SRLR	B
	JMPR	..SHIFT

..RESET.PRINT.SWITCH:

	MVI	A, ON
	SRLR	B
	JC	..SKIP

	CMA

..SKIP:

	STA	PRINTING.SWITCH

	RET


;                           LIBRARY:
;                           -------


;		LIBRARY SUBROUTINE FILES ARE .INSERTed
;		AS REQUIRED, AND ARE NOT ORDINARILY
;		LISTED, TO SAVE TIME AND PAGES.

;		LISTINGS CAN BE OBTAINED VIA
;		THE "LIBRARY" SWITCH, IF DESIRED.


;                          ---------
;                          SAVES.LIB:
;                          ---------
                             .SLIST
                             .XLIST
                    .IFE  LIBRARY - ON, .LIST


;		USED BY MANY, MANY LIBRARY PROCEDURES

REG.SAVE:

	SHLD	..HL.SAVE

	XTHL
	PUSH	X
	PUSH	Y
	PUSH	D
	PUSH	B
	PUSH	H

	LHLD	..HL.SAVE

	RET

..HL.SAVE:

	.WORD	0

REG.RESTORE:

	POP	H
	POP	B
	POP	D
	POP	Y
	POP	X
	XTHL

	RET
                             .RLIST


;                         -----------
;                         CONSOLE.LIB:
;                         -----------
                             .SLIST
                             .XLIST
                    .IFE  LIBRARY - ON, .LIST


;                     CONSOLE CHARACTER  I/O:
;                     ------- ---------  ---


IF.KEY.GET:

;		GET CHARACTER, IF AVAILABLE.
;		IF NOT, RETURN ZERO IN "A":

	CALL	REG.SAVE

Š	MVI	C, CONS.DIRECT
	MVI	E, SET
	CALL	SYSTEM
	CPI	ZERO

	CALL	REG.RESTORE

	RET

GETCHAR:

;		CP/M "UNCONDITIONED" CHARACTER FETCH:

	CALL	REG.SAVE

ŠGETC1:
	MVI	C, CONS.DIRECT
	MVI	E, SET
	CALL	SYSTEM
	CPI	ZERO
	JRZ	GETC1

	CALL	REG.RESTORE

	RET

TO.UPPER:
	ANI	7FH
	CPI	'a'
	RM
	CPI	'z' + 1
	RP
	SUI	20H

        RET

GET.LINE:

;		CP/M EDITED LINE INPUT:

	CALL	REG.SAVE

	MVI	C, READ.LINE
	LXI	D, CONSOLE.BUFFER
	CALL	SYSTEM

	CALL	REG.RESTORE

	RET

PUTCHAR:
ECHO:
	PUSH	PSW
	CALL	REG.SAVE

	MOV	E, A
	MVI	C, CONS.OUTPUT
	CALL	SYSTEM

	CALL	REG.RESTORE
	POP	PSW

	RET

FLASH:

;		SEND STRING TO SCREEN:

	PUSH	PSW
	CALL 	REG.SAVE

..FL1:
	LDAX	D
	CPI	END.MESSAGE
Š	JRZ	..FL2

	CALL	PUTCHAR
	INX	D
	JMPR	..FL1

..FL2:
	CALL	REG.RESTORE
	POP	PSW

	RET



;                  CONSOLE UTILITY:
;                  ------- -------


CRLF:
	PUSH	PSW

	MVI	A, CR
	CALL	PUTCHAR
Š	MVI	A, LF
	CALL	PUTCHAR

	POP	PSW

	RET

CRET:
	PUSH	PSW

	MVI	A, CR
	CALL	PUTCHAR

	POP	PSW

	RET

LFEED:
	PUSH	PSW

	MVI	A, LF
	CALL	PUTCHAR

	POP	PSW

	RET

SPC5:
	PUSH	PSW
	CALL	REG.SAVE

	MVI	B, 5
	CALL	SSPC

	CALL	REG.RESTORE
	POP	PSW
Š
	RET

SSPC:

..SS1:
	MVI	A, SPACE
	CALL	PUTCHAR
	DCR	B
	JRNZ	..SS1

	RET

;                     CONSOLE CONTROL AREA:
;                     ------- ------- ----


                       .LOC  DEF.CONS.BUFF


CONSOLE.BUFFER:

	COM.TAIL.LENGTH:
	MAX.LINE:
			.BLKB	1

	COMMAND.TAIL:
	CHAR.COUNT:
			.BLKB	1

	LINE.IN:
			.BLKB	7EH


			.RELOC
                             .RLIST


;                         -----------
;                         PRINTER.LIB:
;                         -----------
                             .SLIST
                             .XLIST
                    .IFE  LIBRARY - ON, .LIST


;                       PRINTER CONTROL:
;                       ------- -------


PRCHAR:

	PUSH	PSW
	CALL	REG.SAVE

	MOV	E, A

	MVI	C, LIST.CHAR
	CALL	SYSTEM

	CALL	REG.RESTORE
	POP	PSW

	RET
 
PRINT:

	PUSH	PSW
	CALL	REG.SAVE

..RE.PRINT:

	LDAX	D
	INX	D
	CPI	END.MESSAGE
	JRZ	..END.PRINT

	CALL	PRCHAR

	JMPR	..RE.PRINT

..END.PRINT:

	CALL	REG.RESTORE
	POP	PSW

	RET
                             .RLIST


;                         ------------
;                         DATASUBS.LIB:
;                         ------------
                             .SLIST
                             .XLIST
                    .IFE  LIBRARY - ON, .LIST


;                        DATA MANAGEMENT:
;                        ---- ----------


STRCPY:

;		MOVE THE STRING ADDRESSED BY "HL"
;		TO THE DESTINATION IN "DE":

	PUSH	PSW
	CALL	REG.SAVE

..MOV:

	MOV	A, M
	STAX	D

	CPI	NULL
	JRZ	..END

	INX	H
	INX	D
	JMPR	..MOV

..END:

	CALL	REG.RESTORE
	POP	PSW

	RET


STRCAT:

;		ADD THE STRING ADDRESSED BY "DE"
;		TO THE STRING ADDRESSED BY "HL":

	PUSH	PSW
	CALL	REG.SAVE

..FIND:

	MVI	A, NULL
	CMP	M
	JRZ	..ADD
	INX	H
	JMPR	..FIND

..ADD:

	XCHG
	CALL	STRCPY

	CALL	REG.RESTORE
	POP	PSW

	RET


STRCMP:

;		COMPARE THE STRING POINTED BY "DE"
;		TO THAT POINTED BY "HL",
;		RETURNING THE COMPARISON RESULT
;		IN THE ACCUMULATOR:
;
;		      HL > DE    ==   +1
;                     HL = DE    ==    0
;		      HL < DE    ==   -1

	CALL	REG.SAVE

..COMPARE:

	LDAX	D
	CMP	M
	JRNZ	..FAULT

	CPI	NULL
	JRZ	..EXIT

	INX	D
	INX	H
	JMPR	..COMPARE

..FAULT:

	MVI	A, 1
	JC	..EXIT

	NEG

..EXIT:

	CALL	REG.RESTORE
	ORA	A

	RET


STRLEN:

;		FIND LENGTH OF STRING IN "HL";
;		VALUE RETURNED IN "BC".
;		STRINGS LESS THAN 256 BYTES CAN
;		BE READ DIRECT FROM "A" ON RETURN.
;		CALLING VALUE RETURNED IN "HL".
;		WORKS ON NULL STRINGS.

	PUSH	H

	LXI	B, ZERO
	MVI	A, NULL

..STR1:
	CMP	M
	JRZ	..STR2

	INX	H
	INX	B
	JMPR	..STR1

..STR2:
	MOV	A, C

	POP	H

	RET


UP.CASE.STRING:

;		SHIFT THE STRING IN "HL":

	PUSH	PSW
	PUSH	H

..LOOP:

	MOV	A, M
	CPI	NULL

	JRNZ	..UP1

	POP	H
	POP	PSW

	RET

..UP1:
	CALL	TO.UPPER
	MOV	M, A
	INX	H
	JMPR	..LOOP


MOVE:

;		MOVE  #BYTES  IN "BC"
;		FROM LOCATION IN "HL"
;		TO LOCATION IN "DE"
;		AUTOMATICALLY SELECTS
;		PROPER UP/DOWN STRATEGY
;		IN OVERLAPPING MOVES:

	PUSH	PSW
	CALL	REG.SAVE

	MOV	A, B
	ORA	C
	JRNZ	..STRATEGY

	CALL	REG.RESTORE
	POP	PSW

	RET

..STRATEGY:

	PUSH	H
	STC
	CMC
	DSBC	D
	POP	H
	JC	..UP

..DOWN:
	LDIR

	CALL	REG.RESTORE
	POP	PSW

	RET
..UP:
	DAD	B
	DCX	H
	XCHG
	DAD	B
	DCX	H
	XCHG

	LDDR

	CALL	REG.RESTORE
	POP	PSW

	RET


FILL:

	CALL	REG.SAVE
	PUSH	PSW

	MOV	A, B
	ORA	C
	JRNZ	..FIL1

	POP	PSW
	CALL	REG.RESTORE

	RET

..FIL1:

	POP	PSW

	MOV	M, A
	INX	H
	DCX	B

	PUSH	PSW

	MOV	A, B
	ORA	C
	JRNZ	..FIL1

	POP	PSW
	CALL	REG.RESTORE

	RET


SUBSCRIPT:

;		RETURN POINTER TO TABULAR ELEMENT,
;		BASED ON TABLE ORIGIN IN "HL",
;		ELEMENT SIZE IN "B", AND
;		SUBSCRIPT VALUE IN "A":

	CPI	ZERO
	RZ

	PUSH	D
	MVI	D, ZERO
	MOV	E, B

..SUB1:
	DAD	D
	DCR	A
	JRNZ	..SUB1

	POP	D

	RET


INDIRECT:

;		RETURN VALUE POINTED BY "HL"
;		IN "HL" ITSELF, READY
;		FOR SUBSEQUENT INDIRECT ACCESS:

	PUSH	D
	MOV	E, M
	INX	H
	MOV	D, M
	XCHG
	POP	D

	RET


D.CONVERT:

;		CONVERT BINARY ( <100 ) IN ACCUMULATOR
;		TO HIGH DIGIT IN "A" / LOW IN "B";
;		ASCII, WITH LEADING ZERO SUPPRESSED:

	MVI	B, ZERO

..TENS:

	SUI	^D10
	JC	..UNITS

	INR	B
	JMPR	..TENS

..UNITS:

	ADI	^D10
	ADI	'0'

	PUSH	PSW
	MOV	A, B
	POP	B

	ADI	'0'
	CPI	'0'
	JRNZ	..DIGIT

	MVI	A, SPACE

..DIGIT:

	RET
                             .RLIST


;                          ----------
;                          FILEIO.LIB:
;                          ----------
                             .SLIST
                             .XLIST
                    .IFE  LIBRARY - ON, .LIST


;                         FILE ACCESS:
;                         ---- ------


;		ALL SUBROUTINES ASSUME FCB AT DEFAULT


ZERO.FCB:

;		ZERO OUT ALL DATA FIELDS IN DEFAULT FCB
;		EXCEPT THE "DRIVE.SELECTOR" BYTE,
;		THE "FILENAME", AND "FILETYPE" FIELDS:

	LXI	H, FILE.EXTENT.NO
	LXI	B, DISK.BUFFER - FILE.EXTENT.NO
	MVI	A, ZERO

	CALL	FILL

	RET

PREPARE.FCB:

;		MOVE FILE NAME AND TYPE, POINTED
;		INDIRECTLY BY "HL" AND "DE"
;		RESECTIVELY, TO THEIR PROPER
;		POSITIONS IN THE DEFAULT FCB,
;		PADDING WITH SPACES AS REQUIRED.
;		THEN ZERO OUT ALL OF THE REMAINING
;		DATA FIELDS:

	PUSH	D
	PUSH	H

	LXI	H, FILENAME
	MVI	A, SPACE
	LXI	B, 0BH
	CALL	FILL

	POP	H
Š	CALL	INDIRECT
	CALL	STRLEN
	LXI	D, FILENAME
	CALL	MOVE

	POP	H
	CALL	INDIRECT
	CALL	STRLEN
	LXI	D, FILETYPE
	CALL	MOVE

	CALL	ZERO.FCB

	LXI	H, FILENAME
	CALL	UP.CASE.STRING

	RET

OPEN.FILE:

	CALL	ZERO.FCB
	MVI	C, 0F
	LXI	D, FCB
	CALL	SYSTEM
	CPI	0
Š	JP	..OK1

..BUM:
	MVI	A, NOT.OK	; NO MATCH FOUND

	RET

..OK1:
	CPI	4
	JP	..BUM

	XRA	A

	RET

SIZE.FILE:

;	RETURN SIZE OF FILE SELECTED BY DEFAULT FCB
;	IN SECTORS, IN "FILE.LENGTH" FIELD (FCB):

	MVI	C, 23
	LXI	D, FCB
	CALL	SYSTEM

	RET

SET.DMA:

;		DMA ADDRESS SET TO "DE":

	MVI	C, 1A
	CALL	SYSTEM

	RET

SEQ.READ:

	MVI	C, 14
	LXI	D, FCB
	CALL	SYSTEM
	CPI	OK

	RZ

	MVI	A, NOT.OK

	RET

;                      DISK CONTROL AREA:
;                      ---- ------- ----


                          .LOC  DEF.FCB


FCB:

	DRIVE.SELECTOR:
			.BLKB	1

	FILENAME:
			.BLKB	8

	FILETYPE:
			.BLKB	3

	FILE.EXTENT.NO:
			.BLKB	1

	..RESERVED.CPM:
			.BLKB	2

	EXTENT.LENGTH:
			.BLKB	1

	MAP.AREA:
			.BLKB	1

	NEW.NAME:
			.BLKB	0FH

	SEQ.POINTER:
			.BLKB	1

	RAN.POINTER:
	FILE.LENGTH:
			.BLKB	3


DISK.BUFFER:
			.BLKB	80H


			.RELOC
                             .RLIST


;                         -----------
;                         PARSING.LIB:
;                         -----------
                             .SLIST
                             .XLIST
                    .IFE  LIBRARY - ON, .LIST


;                           PARSING:
;                           -------


MARK.END:

;		MARK END OF CONSOLE INPUT STRING
;		WITH NULL, BASED ON
;		STRING ORIGIN IN "HL", AND
;		STRING LENGTH IN "A":

	PUSH	H
	PUSH	D

	MOV	E, A
	MVI	D, ZERO
	DAD	D
	MVI	M, NULL

	POP	D
	POP	H

	RET
	
PARSE.LINE:

;		GIVEN INPUT STRING AT "HL",
;		STORE ADDRESSES OF UP TO 8
;		INDIVIDUAL ARGUMENTS SEQUENTIALLY IN
;		GLOBALLY ADDRESSABLE "ARGV[]" VECTOR;
;		NUMBER OF ARGUMENTS IN "ARGC".
;		AUTO-TERMINATE EACH ARGUMENT IN NULL:

	PUSH	H

	MVI	A, ZERO
	STA	ARGC

..P1:
	CALL	..NON.SPACE
	CPI	NULL
	JRZ	..P2
	CALL	..STASH.POINTER

	CALL	..NEXT.SPACE
	CPI	NULL
	JRZ	..P2
	MVI	M, NULL
	INX	H
	JMPR	..P1

..P2:
	POP H

	RET

..NON.SPACE:

	MOV	A, M
	CPI	NULL
	RZ
	CPI	SPACE
	RNZ
	INX	H
	JMPR	..NON.SPACE

..NEXT.SPACE:

	MOV	A, M
	CPI	NULL
	RZ
	CPI	SPACE
	RZ
	INX	H
	JMPR	..NEXT.SPACE

..STASH.POINTER:

	LDA	ARGC
	CPI	8
	RP

	PUSH	D
	PUSH	H

	LXI	H, ARGV
	MVI	B, 2
	CALL	SUBSCRIPT
	POP	D
	MOV	M, E
	INX	H
	MOV	M, D
	XCHG

	LDA	ARGC
	INR	A
	STA	ARGC

	POP	D

	RET

ARGC:
		.BYTE	0

ARGV:
		.WORD	0, 0, 0, 0, 0, 0, 0, 0


ANALYZE.FILESPEC:

;		SCREEN FOR 0 OR 1 "PERIOD",
;		SCREEN FOR "." FILENAME,
;		BISECT THE ARGUMENT, IF REQ'D,
;		INTO "NAME" AND "TYPE" STRINGS,
;		TERMINATED IN NULLS.
;		CHECK LENGTHS OF THE "NAME"
;		AND "TYPE" FIELDS.
;		ADDRESSES OF ..NAME AND ..TYPE
;		POINTERS RETURNED IN "HL" AND "DE",
;		RESPECTIVELY.  RETURNS NON-ZERO
;		VALUE IN "A" IF FILESPEC IS INVALID:

	LXI	H, ARGV
	CALL	INDIRECT
	SHLD	..NAME
	CALL	STRLEN
	DAD	B
	SHLD	..TYPE

	LHLD	..NAME
	CALL	..PERIOD.COUNT

	CPI	2
	JP	..TROUBLE

	CPI	ZERO
	JRZ	..OK

	CALL	STRLEN
	CPI	1
	JRZ	..TROUBLE

	CALL	..BISECT

..OK:

	LHLD	..NAME
	CALL	STRLEN
	CPI	9
	JP	..TROUBLE

	LHLD	..TYPE
	CALL	STRLEN
	CPI	4
	JP	..TROUBLE

	LXI	H, ..NAME
	LXI	D, ..TYPE
	MVI	A, OK

	RET

..TROUBLE:

	MVI	A, NOT.OK

	RET

..PERIOD.COUNT:

	PUSH	H

	MVI	B, ZERO

..PER1:
	MOV	A, M
	CPI	NULL
	JRZ	..PER3

	CPI	'.'
	JRNZ	..PER2

	INR	B

..PER2:
	INX	H
	JMPR	..PER1

..PER3:
	MOV	A, B

	POP	H

	RET

..BISECT:

	LHLD	..NAME
	MVI	A, '.'

	CCIR

	SHLD	..TYPE
	DCX	H
	MVI	M, NULL

	RET

..NAME:
	.WORD	0

..TYPE:
	.WORD	0
                             .RLIST
                              .PAGE
                   .SBTTL  "DATA ALLOCATIONS"

;    **************************************************
;    **************************************************



;                             ***
;                             RAM:
;                             ***



		  .LOC   ( . + 0F ) & 0FFF0

Š

;                      PROGRAM VARIABLES:
;                      ------- ---------


ARG.POINTER:                   ; FOR COMMAND-TAIL
		.BYTE	ZERO   ; PROCESSING


RULER.SWITCH:
		.BYTE	OFF    ; DISABLES RIGHT MARGIN


DISABLE.UNDERLINE:             ; DISABLES UNDERSCORING
			       ; IN CASE OF PROBLEMS
		.BYTE	CLEAR  ; WITH THE DAMN PRINTER

UNDERLINE:
		.BYTE	0      ; "CONTROL-S"  TOGGLE


COPIES.REQUESTED:

		.BYTE	1	; TO ENABLE MULTIPLES


PAGE.MAP:			; ENABLES PRINTING OF
		.BLKB	8	; SELECTED PAGES

PRINTING.SWITCH:
		.BYTE	0


SIZE.SAVE:
		.WORD	0

BUFF.POINTER:
		.WORD	0


COPY.NO:
		.BYTE	0

PAGE.NO:
		.BYTE	0

LINE.NO:
		.BYTE	0

COLUMN.NO:
		.BYTE	0


CR.FLAG:
		.BYTE	0

LF.FLAG:
		.BYTE	0


                       .IFE  DEBUG - ON, [

		    .LOC  ( . + 0F ) & 0FFF0

PATCH.AREA:

		.BLKB	100H

                             .XLIST      ]
                              .PAGE
                   .SBTTL  "STACK RESERVATION"

;   ***************************************************
;   ***************************************************



;                            *****
;                            STACK:
;                            *****



		    .LOC  ( . + 0F ) & 0FFF0


                      .BLKW     STACK.SIZE


			   TOP.STACK:



PRINT.BUFFER:
                      .BLKB     BUFFER.SIZE
END.BUFFER:



;    **************************************************
;    **************************************************



;                         ***********
;                           ASSEMBLY
;                         TERMINATION:
;                         ***********


                              .LIST


                              LAST:


                SIZE.PROGRAM   ==   LAST - FIRST



;    **************************************************
;    **************************************************
;    **************************************************



                          .END	FIRST

