.comment \

			     TYPEL.MAC v3.5

		     (c) 1984 ESKAY Software Services
			   7120 Skillman #2104
			    Dallas, TX  75231


NOTE:
=====
	If you feel the urge to "improve" this program,
	PLEASE, call the SENECA RCPM first to see if there
	is a later version. THEN send me your update.

 Created from the LDIR code in LDIR12, LTYPE17, SYSLIB routines, and,
 of course, thanks to Dave Rand for the USQ baseline code.

 Revision history:

 08/19/84	Rewrote USQB, added prompted mode
 07/21/84	Allowed type of $SYS files, adapted for SYSLIB3
 07/07/84	Fixed bug introduced in 3.2
 05/23/84	Fixed problem with end-of-file detection
 05/06/84	Added $L argument option
 04/14/84	General cleanup, added $N argument option
 02/15/84	Fixed problem in lbr member filename scanner
 02/13/84	Single file mode skipped logging - could only
		type files in default drive/user.
 02/12/84	MAJOR REVISION AND NAME CHANGE v2.00
		Program now called TYPEL. It is now able to type
		(almost) any single file. See doc for more info
 01/25/84	Added display of original file name if squeezed.
 01/20/84	Made M80/L80 compatible, changed drive/user code
		to allow use in restricted area if already logged.
		Added page mode.
 01/06/84	Rewrote part of LTYPE to allow reconfig without
		reassembly, other minor mods. SFK
 12/09/83	Fixed ^C bug (problem with CONDIN when remote active)
		also fixed problem with 0-length files.	SFK
 12/09/83	Added code to save/restore default drive/user	SFK.
 11/29/83	Made ^C and ^S checks more frequent to fix a problem
		which sometimes caused it to ignore ^C. SFK
 11/24/83	Strips bit 7, made MAXLIN a DB at 101H
 11/20/83	Initially written.

 For further info and reassembly instructions read the DOC file!
\
.8080
;
	EXTRN	BBLINE	;SYSLIB line input
	EXTRN	CCOUT	;SYSLIB character out (convert ctl chars)
	EXTRN	CLOUT	;SYSLIB list char out
	EXTRN	COMPB	;SYSLIB compare .DE-.HL
	EXTRN	CIN	;SYSLIB character in
	EXTRN	DIVHD	;SYSLIB HL DIV DE
	EXTRN	F$OPEN	;SYSLIB open file
	EXTRN	F$READ	;SYSLIB file read
	EXTRN	BDOS	;SYSLIB BDOS call
	EXTRN	FNAME	;SYSLIB file name parser
	EXTRN	PUTUD	;SYSLIB save current DU
	EXTRN	GETUD	;SYSLIB restore default DU
	EXTRN	LOGUD	;SYSLIB log drive/user
	EXTRN	PRINT	;SYSLIB print routine
	EXTRN	PSTR	;SYSLIB print <HL>
	EXTRN	R$READ	;SYSLIB random read
	EXTRN	RETUD	;SYSLIB return drive/user
;
	EXTRN	USQ	;Baseline USQ code
	EXTRN	UINIT	;USQ init code
	PUBLIC	FCB
	PUBLIC	BUFF	;start of buffer
	PUBLIC	TOPRAM	;end of buffer location
	PUBLIC	EREXT	;error intercept from USQ
	PUBLIC	TABLE	;1032 bytes
	PUBLIC	BUFULL	;buffer full (print) routine
;
.request usqb,syslib		;take the workload off the user
;
cr	equ	0dh
lf	equ	0ah
argch	equ	'$'		;option delimiter
;
bufsz	equ	1		;buffer size in K bytes
dbuf	equ	80h		;default buffer
dfcb	equ	5ch		;default fcb
;
begin:	jmp	skipc
maxdrv:	db	1+'B'-40H	;highest accessible drive + 1 (A=2)
maxusr:	db	1+30		;highest accessible user + 1
maxlin:	db	80		;number of lines to print max (0=all)
maxlps:	db	23		;max lines per screen -1 (0= no page)
lsten:	db	0		;zero=list disable, nz=list enable
sysen:	db	0		;zero=no sys files, nz=sys files ok
;
; refuse to type these file types
; (note that type check is done after USQ so no need to
; check for .CQM etc)
;
notyp:	db	'COM'		
	db	'OBJ'		;renamed COM
	db	'LBR'		;library
	db	'OV?'		;OVR,OVL,OV1,OV2 etc
	db	'ARC'		;archive file
;	db	'DIR'		;archive directory
	db	'BAD'		;locked out bad spot
;	db	'SYS'		;system file
	db	'??#'		;specially marked file (USERS.TX# etc)
;	db	'LOG'		;log file
	db	'INT'		;intermediate file (CBASIC etc)
	db	'REL'		;relocatable object file
	db	'?RL'		;PRL, CRL, IRL
;	db	'CMD'		;hard to say... (dbase ok, cp/m86 no-go)
	db	'EXE'		;executable MSDOS file, renamed COMs
	db	0		;end of table
	ds	9*3		;room for 9 more types
;
skipc:	lxi	sp,stack	;set up local stack
	call	print
	db	'TYPEL v3.49 (c) ESKAY 10-07-84',cr,lf,0
	lxi	h,dbuf		;point to buffer
	mov	b,m		;char count to b
	inr	b
arglp:	dcr	b
	jz	sk1
	inx	h
	mov	a,m
	cpi	argch		;check for option delimiter
	jnz	arglp
	dcx	h
	mov	a,m
	inx	h
	cpi	' '		;option must come after a blank
	jnz	arglp
	dcx	h
	mvi	m,0		;remove option
	inx	h
	inx	h		;point to arg
	mov	a,m
	cpi	'N'		;N=nopage
	mvi	m,0
	jz	na
	cpi	'L'
	jnz	exarg
	sta	lout
na:	xra	a
	sta	maxlps		;non paging
exarg:	lda	lsten
	ora	a
	jnz	sk1
	sta	lout
sk1:	call	putud		;save default DU
	lxi	d,bufsz*1024	;compute...
	lxi	h,buff		;...buffer size
	dad	d		;for disk read
	mov	a,h
	sta	topram
	call	retud		;get current drive/user
	mov	a,c
	ora	a
	jz	no00
	mov	h,b
	mov	l,c
	shld	userno		;save current DU
	lda	dfcb+1		;check if no file name specified
	cpi	' '
	jnz	single
loop:	call	print
	db	cr,lf,'* ',0
	mvi	a,1
	sta	singfl
	call	bbline
	call	print
	db	cr,lf,lf,0
	ora	a
	jz	finish
	lxi	sp,stack
	jmp	nextfl
;
stlin:	lda	maxlin		;max number of lines displayed
	sta	maxls
	sta	maxls1
	lda	maxlps
	ora	a
	jz	mls
	dcr	a		;first page is one less than normal
mls:	sta	lps
	ret
;
single:	lxi	h,dbuf+2	;point to argument
nextfl:	lxi	d,fcb
	call	stlin
	call	fname		;parse file name
	jz	what		;not a valid file name
	mov	a,m		;get delimiter
	sta	fflag		;set flag LBR/non-LBR
	push	h		;save command line ptr
	inx	b		;check if current DU:
	mov	a,b
	ora	c
	dcx	b		;restore DU: value
	jz	currdu		;skip this if current
	call	print
	db	cr,lf,lf
	db	'Can only display current drive/user!',cr,lf,lf,0
	rst	0

	mov	a,b		;get specified drive
	dcr	b		;get into range 0..f
	cpi	0ffh		;ff means current drive
	lxi	h,maxdrv
	jnz	newdsk		;skip if different
	lda	driveno
	mov	b,a
	jmp	curdsk
;
newdsk:	cmp	m
	jnc	illdu		;yes - complain
curdsk:	mov	a,c		;get specified user area
	cpi	'?'		;all user areas???
	jz	illdu		;yes - complain
	cpi	0ffh		;current user area?
	jnz	newusr
	lda	userno
	mov	c,a
	jmp	curusr
;
newusr:	inx	h		;illegal user specified?
	cmp	m
	jnc	illdu		;yes - complain
curusr:	call	logud		;log into specified DU:
currdu:	lda	fflag		;get flag
	cpi	' '		;LBR member request?
	pop	h		;get cmd line ptr back
	jnz	nolbf		;nope, must be singlefile
	inx	h		;get next char
	lxi	d,memfcb	;point to member fcb
	call	fname		;parse member name
	lxi	h,fcb+1
	call	ckamb		;check ambiguity
	lxi	h,memfcb+1
	call	ckamb
	lxi	h,FCB+9		;default to .LBR
	mvi	m,'L'
	inx	h
	mvi	m,'B'
	inx	h
	mvi	m,'R'
	lxi	d,fcb
	call	f$open		;attempt to open file
	jnz	nofile		;not a LBR file
	xra	a
	sta	dirs		;set directory check size to 0
	lda	sysen		;if $SYS suppress
	ora	a		;then...
	cz	sysck		;check for $sys bit
	xra	a
	sta	lin		;set line count to 0
	lxi	h,memfcb+9	;point to member type
	call	typck		;check valid type
	call	f$read		;read directory into default buffer
	jnz	rderr
	lxi	h,dbuf		;point to dbuf
	lxi	d,dirname	;point to 8 blanks
	call	cpfn		;compare
	jnz	nolbr		;not equal
	lxi	d,14
	dad	d
	mov	a,m
	sta	dirsiz		;directory size
	xra	a
	sta	memfcb
	jmp	c00		;skip into directory check
;
dirlp:	lxi	d,fcb
	call	f$read
	jnz	rderr
c00:	lxi	b,20h
	lxi	h,dbuf
	lxi	d,memfcb
	call	cpfn
	jz	found
	dad	b
	call	cpfn
	jz	found
	dad	b
	call	cpfn
	jz	found
	dad	b
	call	cpfn
	jz	found
	lda	dirs
	inr	a
	sta	dirs
	mov	b,a
	lda	dirsiz
	cmp	b
	jnz	dirlp
	call	print
	db	cr,lf
	db	'Member file not found in LBR directory',cr,lf,0
	jmp	erext
;
; Found the member file name in the LDIR
;
found:	lxi	d,12
	dad	d
	push	h		;save pointer for now,
	inx	h		;point to size
	inx	h
	mov	a,m		;get low byte
	inx	h
	ora	m		;if a=0 then file is 0k
	jz	nullen		;go complain
	pop	h		;get pointer back
	mov	a,m		;get file address
	inx	h
	mov	h,m
	mov	l,a
;
; enter here from non-LBR routine with HL=0000
;
dotyp:	lxi	d,fcb		;get fcb...
	call	r$read		;...and read random
	jnz	rderr
	lxi	b,dbuf		;point to buffer
	ldax	b		;get first byte
	cpi	76h		;if not 76H (=not squeezed)...
	jnz	plain		;...then process as text
	inx	b		;point to and...
	ldax	b		;...get next byte
	cpi	0ffh		;if FF then squeezed..
	jnz	plain		;...else plain text (?)
	call	uinit
	lxi	h,dbuf+4	;point to original name
	call	chktp		;check it's type
	mvi	a,'('		;print the original name...
	call	ccout		;...in parentheses
	lxi	h,dbuf+4
	call	pstr
	call	print
	db	')',cr,lf,0
	call	usq		;now unsqueeze and print
	jmp	goteof
;
; This routine fills the buffer then calls the print routine
;
plain:	lxi	d,fcb
	lxi	b,dbuf		;default buffer
fnext:	lxi	h,buff
rdlp:	call	f$read		;changed to properly detect eof...
	jnz	goteof		;...in unsqueezed single files
mlp:	ldax	b
	mov	m,a
	inx	h
	inr	c
	jnz	mlp
	mvi	c,80h
	lda	topram
	cmp	h
	jnz	rdlp
	call	bufull		;print buffer contents
	jmp	fnext
;
goteof:	call	bufull
	jmp	erext
;
; This is the print buffer routine (BUFULL)
;
bufull:	push	h
	push	d
	push	b
	push	psw
	lxi	h,buff
buflp:	mov	a,m
	cpi	1ah
	jz	erext
	cpi	'I'-40h
	jz	proctab
	ani	7fh		;strip high bits
	call	putchr
	cpi	lf
	jz	eoln
	call	condin		;get keybd char if available
	jz	goon		;none there, go on
	cpi	'C'-40h		;if ^C...
	jz	erext		;...then finished
	cpi	'S'-40h		;if not ^S...
	jnz	goon		;...then go on, else...
	call	cin		;...wait for keypress
	cpi	'C'-40h
	jz	erext
	jmp	goon
;
; This is NOT the SYSLIB routine by same name...
;
condin:	push	h
	push	d
	push	b
	mvi	c,6
	mvi	e,0ffh
	call	bdos
	ora	a
	pop	b
	pop	d
	pop	h
	ret
;
eoln:	mvi	a,0ffh		;reset tab counter
	sta	tab
	lda	maxlps		;get max lines per screen
	ora	a
	jz	nopag		;skip if no page mode
	lda	lps
	dcr	a
	sta	lps
	jnz	nopag
	call	print
	db	'[more]',cr,0
	call	cin
	cpi	'C'-40h
	jz	erext
	call	print
	db	'      ',cr,0
	lda	maxlps
	sta	lps
nopag:	mvi	a,0		;filled by program
maxls	equ	$-1		;if maxln=0...
	ora	a
	jz	goon		;..then skip line counter
	lda	lin		;else increment...
	inr	a
	sta	lin		;...the line counter
	cpi	0		;see if maxlin reached
maxls1	equ	$-1
	jnz	goon		;no, continue
	call	print		;else abort with message
	db	cr,lf
	db	'TYPEL aborted  - maximum number of lines exceeded.',cr,lf
	db	'Please use XMODEM to transfer file to your system.'
	db	cr,lf,lf,0
	jmp	erext
;
proctab:lda	tab		;get current tab value
	mov	b,a		;save current
	ani	0f8h		;round down to last full 8
	adi	8		;make next tab stop
tablp:	call	spout		;put space
	inr	b		;continue spaces to..
	cmp	b		;...next tab stop
	jnz	tablp
	sta	tab		;save next tab stop
	jmp	go1
;
; Print a space
;
spout:	push	psw
	mvi	a,' '
	call	putchr
	pop	psw
	ret
;
goon:	lda	tab		;increment...
	inr	a
	sta	tab		;...tab counter
go1:	inx	h		;increment buffer pointer
	lda	topram		;get top of ram
	cmp	h		;if not yet reached...
	jnz	buflp		;...then get next char
	pop	psw		;else return to caller...
	pop	b		;...to get more
	pop	d
	pop	h
	ret
;
; process non-LBR file
;
nolbf:	lxi	h,fcb+1
	call	ckamb
	lxi	h,fcb+9		;point to type
	call	typck		;check valid type
	lxi	d,fcb
	call	f$open		;open the file
	jnz	nofile		;not found...
	lda	sysen
	ora	a
	cz	sysck		;$sys file?
	call	f$read		;read first sector
	lxi	h,0
	jz	dotyp		;type it now...
	call	print
	db	cr,lf
	db	'Unable to type - empty file?',cr,lf,0
	jmp	erext
;
; check type of squeezed file (HL=original fn)
;
chktp:	push	b
	mvi	b,9		;9 char max
chkt1:	mov	a,m
	inx	h
	cpi	'.'		;end of fn?
	jz	typck1
	dcr	b
	jnz	chkt1
	pop	b
	ret
;
; check file type at <HL> against table
; PSW, HL munched, ret only if ok
;
typck:	push	b
typck1:	push	d
	push	h
	lxi	d,notyp		;point to no-type table
tck1:	pop	h
	push	h
	mvi	b,3		;3 chars to compare
tck2:	ldax	d
	ora	a		;if end of table...
	jz	typok		;...then return
	cpi	'?'		;ambiguous?
	jz	tck3		;yes, skip
	cmp	m		;if no match...
	jnz	tck4		;...then skip to next table entry
	inx	h
	inx	d
	dcr	b
	jnz	tck2		;loop until all 3 match
	pop	h
	pop	d
	pop	b
	jmp	tckno		;not ok to type
;
; skip next character in table and filetype
;
tck3:	inx	h
	inx	d
	dcr	b
	jnz	tck2
	jmp	tck1
;
; skip to next table entry
;
tck4:	inx	d
	dcr	b
	jnz	tck4
	jmp	tck1
;
; restore registers and return (ok to type)
;
typok:	pop	h
	pop	d
	pop	b
	ret
;
; complain and abort (type found in table)
;
tckno:	call	print
	db	cr,lf
	db	'Can''t type a .',0
	mvi	b,3
tcl:	mov	a,m
	inx	h
	call	ccout
	dcr	b
	jnz	tcl
	call	print
	db	' file!',cr,lf,0
	jmp	erext
;
; check if DE+10 has bit 7 set ($SYS file)
;
sysck:	push	h		;save HL
	lxi	h,10
	dad	d
	mov	a,m
	pop	h
	ani	80h
	rz
	jmp	nofile		;pretend not there
;
; Here are the messages
;
illdu:	call	print
	db	cr,lf
	db	'Drive/user out of bounds',cr,lf,0
	jmp	erext
;
nofile:	call	print
	db	cr,lf
	db	'No such file on disk',cr,lf,0
	jmp	erext
;
cpfn:	push	h
	push	d
	push	b
	mvi	b,12	;12 characters
	call	compb
	pop	b
	pop	d
	pop	h
	ret
;
ckamb:	mvi	a,'?'		;see if there is any...
	mvi	e,11		;...ambiguity in the file spec
ckamlp:	cmp	m
	jz	noamb		;complain if ambiguous fn
	inx	h
	dcr	e
	jnz	ckamlp
	ret
;
putchr:	push	b
	mov	b,a
	lda	lout
	ora	a
	mov	a,b
	jnz	cot
	call	ccout
	pop	b
	ret
;
cot:	call	clout
	pop	b
	ret
;
nolbr:	call	print
	db	cr,lf
	db	'LBR directory may be damaged - aborting',cr,lf,0
	jmp	erext
;
nomem:	call	print
	db	cr,lf
	db	'No member file name specified.',cr,lf,0
	jmp	what
;
nullen:	call	print
	db	cr,lf
	db	'Member file is 0k - cannot type.',cr,lf,0
	jmp	erext
;
rderr:	call	print
	db	cr,lf
	db	'Cannot read file',cr,lf,0
	jmp	erext
;
no00:	call	print
	db	cr,lf,lf,7
	db	'ERROR - cannot use in users 0 and 31!',cr,lf,0
	rst	0
;
noamb:	call	print
	db	cr,lf
	db	'No ambiguous file names allowed',cr,lf,0
what:	call	print
	db	cr,lf
	db	'TYPEL v3.5 universal single-file lister',cr,lf
	db	'Usage:',cr,lf
	db	9,'TYPEL [du:]fn[.ft] [fn.ft]',cr,lf
	db	'Examples:',cr,lf
	db	9,'TYPEL MDM722 MDM722.IQF     types member file in LBR',cr,lf
	db	9,'TYPEL TEST.AQM              types normal file',cr,lf
	db	9,'TYPEL F4:TEST.BQS           accepts ZCPR drive/user',cr,lf
	db	9,'TYPEL FOO.ASM $N            $N option=not paging',cr,lf
	db	9,'TYPEL BAR.ZOT $L            $L option=LST: device',cr,lf
	db	'If 1 argument is supplied, single file is typed.',cr,lf
	db	'If 2 arguments, TYPEL assumes first arg is type LBR',cr,lf
	db	'and attempts to type LBR member.',cr,lf
	db	9,'Typing TYPEL without argument starts interactive mode.'
	db	cr,lf,'You can enter individual filenames or RETURN to stop.'
	db	cr,lf,lf,0
erext:	call	getud		;restore default DU
	lda	singfl
	ora	a
	jnz	loop
finish:	rst	0
;
singfl:	db	0		;0=single files, 1=prompted
lout:	db	0		;flag for list out
fflag:	db	0		;flag for LBR/non-LBR
topram:	db	0		;hi byte of buffer end
dirs:	db	0		;# of dir sectors processed
dirsiz:	db	0		;# of total dir sectors
tab:	db	0		;current line tab
lin:	db	0		;line count
lps:	db	0		;line count for page mode
userno:	db	0		;current user #
driveno:db	0		;current drive
fcb:	ds	36		;out fcb
memfcb:	ds	12
	ds	50		;25 level stack
stack:	dw	0		;save CP/M stack pointer here
dirname:db	0,'           '
buff	equ	2000h		;start buffer
table	equ	buff-1048	;usq table
	end
 option=LST: device',cr,lf
	db	'If 1 argument is supplied, single file is typ