issue: ellis book
author: bruce ellis
category: episode 7 programs

[figure 18]

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Program:	Count_frag
;	Author:	        Billy Bitsenbites (Bruce Ellis)
;	Date written:	5/5/90
;	Function:	Prompts for a directory specification,
;			opens the directory file, and uses the
;			file id of the files cataloged in the
;			directory to count the number of file
;			headers and mapping pointers for each
;			file.  Note:  no fancy wildcard processing
;			was included in the interest of brevity.
;			In typical Guide style, if you want it
;			then add it.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;Macro to check status
	.macro	check	arg=r0,?l
	blbs	arg,l
	$exit_s	arg
l:
	.endm	check
;Include system macro library
	.library	/sys$library:lib.mlb/
	$dirdef		;Directory record symbolic definitions
	$fabdef		;File Access Block definitions
	$rabdef		;Record Access Block definitions
	$namdef		;Name Block definitions
;Fab for $PARSE to parse directory specification to fid/did
fab_parse:
	$fab	FNA=dir_spec,FOP=NAM,-
		NAM=dir_nam_blk
;Fab for directory file open
fab1:	$fab	FAC=<GET>,FOP=NAM,-
		MRS=512,ORG=<SEQ>,RFM=<VAR>,-
		SHR=<SHRGET>,NAM=dir_nam_blk
;Rab for directory file processing
RAB1:	$rab	FAB=FAB1,-
		RBF=BUF,RSZ=512,UBF=BUF,USZ=512,-
		ROP=<RLK,WAT>
;Name block for procesing directory fid/did
dir_nam_blk:
	$nam	ESA=dir_spec_p,ESS=nam$c_maxrss
;Record buffer
buf:	.blkb	512
;record number counter
line_counter:	.long	0,0
;format statement for file name
file_fmt:	.ascid	/!AC;!UW/
;full format for output
fmt:	.ascid	/!50AS !9UL !9UL/
;file name descriptor
file_desc:
	.long	255
	.address	10$
10$:	.blkb	255
indexf_channel:		;Storage for indexf channel number
	.blkl	1
header_bias:		;Bias from first header for use with file id
	.blkl	1
pointer_cnt:		;count of mapping pointers
	.blkl	1
header_cnt:		;count of file headers
	.blkl	1
pmt:	.ascid	/Directory spec>/	;prompt for directory spec
dir_spec_d:		;storage for full directory spec
	.long	nam$c_maxrss
	.address	dir_spec
dir_spec:	
	.blkb	nam$c_maxrss
dspd:
	.blkl	1
	.address	dir_spec_p
dir_spec_p:
	.blkb	nam$c_maxrss
device_name:
	.blkl	1	;device name descriptor
devnam_adr:
	.blkl	1
;display buffer
out_buf:.long	512
	.address	10$
10$:	.blkb	512
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Main code 
;	Function:	Prompts for directory spec, opens directory
;			file by file id, reads each record, obtains
;			the count of headers, and displays counts.
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	.entry	file,^m<>
	pushal	dir_spec_d		;Read with prompt
	pushal	pmt			; directory specification
	pushal	dir_spec_d
	calls	#3,g^lib$get_input
	check
	movb	dir_spec_d,fab_parse+fab$b_fns	;parse directory spec
	$parse	fab=fab_parse
	check
	bbs	#nam$v_exp_name,-		;Don't handle file name
		dir_nam_blk+nam$l_fnb,no_exp
	bbs	#nam$v_exp_ver,-		;Don't handle versions
		dir_nam_blk+nam$l_fnb,no_exp
	bbs	#nam$v_exp_type,-		;Don't handle types
		dir_nam_blk+nam$l_fnb,no_exp
	bbs	#nam$v_wildcard,-		;don't handle wildcard
		dir_nam_blk+nam$l_fnb,no_exp
	brb	dir_ok
no_exp:	movl	#ss$_badirectory,r0		;beat it
	ret
dir_ok:	movzbl	dir_nam_blk+nam$b_esl,dspd	;get size of complete string
	subl2	#2,dspd				;skip trailer
	pushal	dspd				;spill the directory spec
	calls	#1,g^lib$put_output
	movl	dir_nam_blk+nam$w_did,-		;Reset dir id to file id
		dir_nam_blk+nam$w_fid
	movw	dir_nam_blk+4+nam$w_did-	;Reset rest of file id
		,dir_nam_blk+nam$w_fid+4
	clrl	dir_nam_blk+nam$w_did		;clear the directory id
	clrw	dir_nam_blk+nam$w_did+4
	movzbl	dir_nam_blk+nam$b_dev,device_name	;Build device name
	movl	dir_nam_blk+nam$l_dev,devnam_adr	; descriptor
	$open	fab=fab1		;open the direcory file
	check
	$connect	rab=rab1	;connect the record stream
	check
	pushal	device_name		;pass device name
	pushal	header_bias		;pass file header bias
	pushal	indexf_channel		;pass the channel address to store
	calls	#3,open_indexf		;open the index file
l:	$get	rab=rab1		;read the first record from the dir 
	cmpl	#rms$_eof,r0 		;at end?
	bneq	check_error		;if not check for other errors
	brw	done			; else scram
check_error:
	check				; 
	moval	buf,r7			;move record address to register
	movzwl	rab$w_rsz+rab1,r6	;get the record size
	ASSUME dir$w_verlimit EQ 2
	subl	#<dir$t_name-2>,r6	;drop count by size of fixed overhead
	movzbl	<dir$b_namecount-2>(r7),r8	;get the size of the file name
	blbc	r8,skip_inc		;if even don't round
	incl	r8			;round to even number of bytes
skip_inc:
	subl	r8,r6			;drop count by size of file name
	divl	#8,r6			;determine the number of versions
	addl3	r8,#<dir$t_name-2+buf>,r9	;determine the start the fids
process_versions:
	pushal	header_cnt		;push location to store header count
	pushal	pointer_cnt		;push location to store pointer count
	pushal	dir$w_fid(r9)		;pass file id
	pushal	header_bias		;pass header bias
	pushal	indexf_channel		;pass channel of indexf.sys
	calls	#5,count_pointers	;count the pointers
	ediv	#22,line_counter,r10,line_counter	;Printed 22 lines?
	tstl	line_counter		;if not skip line header
	bneq	skip_header		; else print line header
	jsb	dump_page_header
skip_header:
	movab	<buf+dir$b_namecount-2>,r4	;get size of file name
;*********
;Format the file name/header count/pointer count
;*********
	$fao_s	ctrstr=file_fmt,outbuf=file_desc,outlen=file_desc,-
		p1=r4,p2=dir$w_version(r9)
	$fao_s	ctrstr=fmt,outbuf=out_buf,outlen=out_buf,-
		p1=#file_desc,p2=pointer_cnt,p3=header_cnt
	pushal	out_buf			;spill file info
	calls	#1,g^lib$put_output
	incl	line_counter
	movl	#255,file_desc
	movl	#512,out_buf		;reset buffer size
	addl	#8,r9			;get next version of file
	sobgtr	r6,process_versions_br	;process next version of file
	brb	next_file
process_versions_br:
	brw	process_versions
next_file:
	brw	l			;get next file
done:
	movl	#ss$_normal,r0		;sayonara
	ret

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;Dump page header
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LF=10
CR=13
page_hdr:	.ascid	$File                                  $-
			$                 Ptr cnt.   Hdr cnt.$<LF><CR>-
			$____                                  $-
			$                 _______    ________$
dump_page_header:
	pushal	page_hdr
	calls	#1,g^lib$put_output
	rsb

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Subroutine:	open_indexf
;	Function:	opens the indexf.sys file
;	Inputs:		4(ap)	channel address
;			12(ap)	device name
;	Outputs:	8(ap)	header bias
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	$fibdef		;File information block offsets
	$hm2def		;Home block offsets
chan_arg=4
bias_arg=8
dev_arg=12
i_fid:	.word	1,1,0	;file id of indexf.sys
fibd:	.long	fib$k_length	;file info block descriptor
	.address	fib
fib:	.blkb	fib$k_length	;file information block
iostat:	.blkq	1	;io status block
block:	.blkb	512	;home block buffer
	.entry	open_indexf,^m<r6,r8,r9>
;Assign channel to device
	$assign_s	devnam=@dev_arg(ap),chan=@chan_arg(ap)
	check
	moval	fib,r6			;get fib descriptor
	movl	i_fid,fib$w_fid(r6)	;set up fid in fib
;******************
;Open indexf.sys
;******************
	$qiow_s	chan=@chan_arg(ap),func=#<io$_access!io$m_access>,-
		iosb=iostat,p1=fibd
	check				;Check status
	check	iostat
;****************
;Read the home block
;****************
	$qiow_s	chan=@chan_arg(ap),func=#io$_readvblk,iosb=iostat,-
		p1=block,p2=#512,p3=#2
	check				;Check status
	check	iostat
	movzwl	hm2$w_ibmapvbn+block,r8		;get index bitmap VBN
	movzwl	hm2$w_ibmapsize+block,r9	; and size
	addl	r8,r9				;compute header bias
	decl	r9
	movl	r9,@bias_arg(ap)		;return header bias
	movl	#ss$_normal,r0			;scram
	ret
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Subroutine:	count_pointers
;	Function:	counts the number of mapping pointers
;			and file headers in a file.
;	Inputs:		4(ap)	channel number address for index file
;			8(ap)	header bias
;			12(ap)	file id of file
;	Outputs:	16(ap)	count of mapping pointers
;			20(ap)  count of file headers
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	$fh2def		;Base file header offsets
	$fiddef		;file id offsets
	$fm2def		;mapping pointer offsets
header_num:
	.blkb	4	;local storage for header number
ios:	.blkq	1	;io status block
header_block:		;storage for header block
	.blkb	512
fid_arg=12
ptr_arg=16
hdr_arg=20
	.entry	count_pointers,^m<r2,r3,r4,r6,r7,r8,r9>
	movl	fid_arg(ap),r6			;Get file id address
	movw	fid$w_num(r6),header_num	;Get file header number
	movzbw	fid$b_nmx(r6),header_num+2
	addl3	@bias_arg(ap),header_num,r7	;add biad to header number
	movl	#1,@hdr_arg(ap)			;assume 1 header
	clrl	@ptr_arg(ap)			;clear count of pointers
;****************
;Read header block
;****************
	$qiow_s	chan=@chan_arg(ap),func=#io$_readvblk,iosb=ios,-
		p1=header_block,p2=#512,p3=r7
	check				;check call status
	check	ios			;check completion status
	cmpw	header_block+fh2$w_fid_seq,fid$w_seq(r6)	;check seq #
	beql	got_header
	movl	#ss$_nosuchfile,r0	;if seq # wrong abort
	brw	err_out_counter
got_header:
	moval	header_block,r9		;get header block buffer address
next_ext_header:
	movzbl	fh2$b_mpoffset(r9),r2	;locate mapping pointers
	mull2	#2,r2			; using word offset
	addl	r9,r2			;
next_mapping_ptr:
	movw	(r2)+,r3		;get next pointer
	beql	no_more_pointers	;if none scram
	extzv	#fm2$v_format,#fm2$s_format,r3,r4	;determine format
	mull2	#2,r4			;skip based on word count of pointer
	addl	r4,r2			;
	incl	@ptr_arg(ap)		;bump the pointer count
	brw	next_mapping_ptr
no_more_pointers:
	movaw	fh2$w_ext_fid(r9),r6	;get extension header file id
	movw	fid$w_num(r6),header_num	
	movzbw	fid$b_nmx(r6),header_num+2	
	tstl	header_num		;extension header?
	beql	done_with_pointers	;if so calculate the VBN of
	addl3	@bias_arg(ap),header_num,r7	; the header block
	beql	done_with_pointers	;if none scram
	incl	@hdr_arg(ap)		; else bump header count
;*****************
;Read extension header
;*****************
	$qiow_s	chan=@chan_arg(ap),func=#io$_readvblk,iosb=ios,-
		p1=header_block,p2=#512,p3=r7
	check				;check appropriate status
	check	ios
	moval	header_block,r9		;reset header address
	brw	next_ext_header		;get next header block
done_with_pointers:

	movl	#ss$_normal,r0
err_out_counter:
	ret				;Sayonara
	.end	file
