	.TITLE	MAP - Display a file's mapping information on TI:
	.IDENT	/V01.05/
	.NLIST	BEX
	.ENABL	LC

	.SBTTL	GEN Control

;+
;
; MAC:		ob:map,mp:map/-sp=map
;
; MSG:		For named directory support TKB under M-PLUS only.
;
; TKB:		MAP/PR:0/CP/-FP,MP:MAP/-SP=MAP
;		LB:[1,1]XDTLIB/LB
;		/
;		UNITS=2
;		TASK=...MAP
;		PRI=120
;		STACK=128
;		//
;
;-
	.PAGE
	.SBTTL	Header and Title.
;+
;			--==<< MAP >>==--
;
; Author:	Adrian Bottoms
; Copyright	(C) XDT Computer Consultants 1988
;		9 The Square
;		Keyworth
;		Nottngham	NG12 5JT
;		Great Britain	Tel: (+44) (6077) 5295
;
; Date:		10-Mar-88
; Version:	V01.00
; Purpose:	Display the mapping information about a file.
; Usage:	MAP file[,file...]
;
;		MAP has been written to support named directories under 
;		RSX-11M-PLUS or RSX-11M. This is done transparently by FCS and 
;		CSI routines but in order to do this MAP MUST be TKBed under
;		M-PLUS to get the named directory and logical name support 
;		from the right SYSLIB. It TKBs OK under 11M but does not get
;		the named directory support.
;
; Modified:	Adrian Bottoms
; Date:		12-Apr-88
; Version:	V01.01
; Edit:		AB001
; Purpose:	Make MAP behave sensibly if the file length is 0. (Remeber
;		to test all boundary coditions in future).
;
; Modified:	Adrian Bottoms
; Date:		15-Apr-88
; Version:	V01.02
; Edit:		AB002
; Purpose:	Re-order various bits without changing any code (much) so that
;		MAP gathers all the data for a file and then prints it all out.
;		This is in preparation for the version with wild card support
;		which will write stats to an output file for another programme
;		to process (eg FRED.MAC 240,1,1,140,1...)
;
; Modified:	Adrian Bottoms
; Date:		15-Apr-88
; Version:	V01.03
; Edit:		AB003
; Purpose:	Spurred on by the success of the last mod. add another statistic
;		which gives an indication of the distance across the file. This
;		is obtained by summing the number of blocks from one end of the
;		file to the other taking into account all the 'dead' blocks
;		which lie between retrieval pointers.
;
; Modified:	Adrian Bottoms
; Date:		19-Apr-88
; Version:	V01.04
; Edit:		AB004
; Purpose:	Add a check for files with 2:4 retrieval pointers and ignore
;		them for now.
;
; Modified:	Adrian Bottoms
; Date:		6-Jun-88
; Version:	V01.05
; Edit:		AB004
; Purpose:	Fix problem with processing of the segment count which gave
;		one segment too many for contiguously placed files. Also
;		fix problem with segment minimum size being wrong.
;
; Note:	1)	The traversal path length deserves a few words of explanation.
;		The traversal path is the sum of geometric distance between
;		the start block numbers of adjacent pairs of retrieval pointers
;		plus the length of the last one. This gives an indication of the
;		amount of disc that has to be traversed but may not be the actual
;		disc traversed. While the algorithm used worries about the fact
;		that the area mapped by one pointer may be logically before the
;		previous one it does add in double the size of the previous one
;		(as it should because this area gets traversed twice!). The 
;		traversal path may thus be an underestimate.
;
;-
  
	.SBTTL	Local symbols, system macros etc.

TILUN	== 1				; Lun for TI: I/O.
FILLUN	= 2				; Lun for target file and INDEXF.SYS.

	.LIBRARY	"LB:[1,1]XDTMAC.MLB"  
	.MCALL	DIR$,ALUN$S,FSRSZ$,FDBDF$,FDOP$A
	.MCALL	GCMLB$,CSI$,CSI$1,CSI$2,QIOW$S
	.MCALL	EXST$S,NMBLK$,GCML$,FINIT$
	.MCALL	HMBOF$,FHDOF$,XDTDF$
	HMBOF$
	FHDOF$
	XDTDF$

	.MACRO	PRTDBL	arg
	.IF NB <arg>
	    .IIF DIF arg,R1	MOV	arg,R1
	.ENDC	; IF NB arg
	JSR	PC,PRTDBL
	.ENDM	PRTDBL

	.MACRO	PRTSNG	arg
	.IF NB <arg>
	    .IIF DIF arg,R1	MOV	arg,R1
	.ENDC	; IF NB arg
	JSR	PC,PRTSNG
	.ENDM	PRTSNG

	.MACRO	PERCNT	a,b
	MOV	'a,R2			; Get param 1
	MOV	'b,R1			; Get param 2
	JSR	PC,PERCNT		; Go do the routine.
	.ENDM	PERCNT

	.PAGE
	.SBTTL	Local pure data.
  
	.PSECT	XDTROD	D,RO,LCL,REL,CON
  
DEFNAM:	NMBLK$	,,0,SY,0		; Default filename for input file.

INDEXF:	.WORD	1,1,0			; File ID for INDEXF.SYS
  
	.SBTTL	Local impure data.
  
	.PSECT	XDTRWD	RW,D,LCL,REL,CON
  
	FSRSZ$	1,,XDTRWD		; One FSR needed (for GCML).
FDB:	FDBDF$				; Allocate an FDB for target file.
	FDOP$A	FILLUN,CSIBLK+C.DSDS,DEFNAM,FO.RD!FA.SHR
FNB	= FDB + F.FNB			; Define file name block offset.
FID	= FDB + F.FNB + N.FID		; Define offset to file ID.
  
CMND:	.BLKB	82.			; Command line buffer.
CMNDL	= . - CMND
  
GCML:	GCMLB$	,MAP,CMND,TILUN,,CMNDL	; Get command line control block.

	CSI$				; Set up CSI stuff.
	.EVEN

CSIBLK:	.BLKB	C.SIZE			; Set up CSI control block.
  	.EVEN
  
BLOCK:	.BLKB	512.			; File header block buffer.

OFFSET:	.WORD	0			; Offset down INDEXF.SYS to a file ID.
NHEADS:	.WORD	0			; No. of file headers.
NPNTRS:	.WORD	0			; No. of retrieval pointers.
NSEGS:	.WORD	0			; No. of file segments.
FILSIZ:	.WORD	0,0			; File size.
TRVPTH:	.WORD	0,0			; File traversal path.			; AB003
LSTLBN:	.WORD	0,0			; Saved lbn from pointer.
LSTCNT:	.WORD	0			; Saved count from last pointer.
MINHED:	.WORD	0			; Minimum no. of headers required.
MINPNT:	.WORD	0			; Minimum no. of pointers required.
SEGSIZ:	.WORD	0,0			; Size of current file segment.
SEGMAX:	.WORD	0,0			; Largest file segment size.
SEGMIN:	.WORD	0,0			; Smallest file segment.
ISB:	.BLKW	2			; I/O status block.
ASCBUF:	.BLKB	20.			; GP buffer.

FLAG:	.WORD	0			; Flag word. Cleared at start of -
					;	processing each file.
    F.LCNTG	= 1			; File is logically contiguous (1=YES)
    F.VCNTG	= 2			; File is virtually contiguous (1=YES)
    F.RTV1	= 4			; Handling 1st retrieval pointer (1=YES)
    F.ZLEN	= 10			; File is zero length (1=YES)		; AB001
    F.TWO4	= 20			; File mapped by 2:4 pointers (1=YES)	; AB004

FILBUF:	.BYTE	0,'+			; Count and carriage control.		; AB002
FILSTR:	.BLKB	60.			; Buffer for file name.

	.PAGE
	.SBTTL	Main code.
  
	.PSECT	XDTROC	I,RO,LCL,REL,CON
  
	.ENABL	LSB
MAP::					; Task transfer address.
	MSGTRP	MAP,SST			; Generate MSGTRP support.
	ALUN$S	#TILUN,#"TI,#0		; Assign lun to TI:
	GCML$	#GCML			; Get a command line.
	BCC	2$			; Continue if got one.

	CMPB	#GE.EOF,G.ERR(R0)	; EOF from GCML ??
	JEQ	EXIT			; Yes - That's OK.

	ERROR	<Failed to get a command line.>,FATAL

2$:	FINIT$				; Initialise the file system.
	CSI$1	#CSIBLK,GCML+G.CMLD+2,GCML+G.CMLD
	BCS	4$			; Br if CSI failed.
  
REPEAT:	; Repeat point to multiple files in command line.
	CSI$2	#CSIBLK,OUTPUT		; Try to get a file name.
	BCC	6$			; Got one.
	
4$:	ERROR	<Syntax error in command line.>

6$:	BITB	#CS.EQU,C.STAT(R0) 	; Invalid command line ??
	BCS	4$			; Yes - Go and moan.
  
	BITB	#CS.WLD,C.STAT(R0) 	; Wild cards present ??
	BEQ	8$			; No - Br.
	ERROR	<MAP does not support wild cards (yet!).>,FATAL

8$:	JSR	PC,GETMAP		; Get the map data for the current file.
	JSR	PC,PRTMAP		; Print out the mapping info.		; AB002

	MOV	#CSIBLK,R0		; Point back to CSI control block.
	BITB	#CS.MOR,C.STAT(R0)	; More files to do ??
	BEQ	EXITOK			; No - Br to exit then.

	; More files in the command line to map. Propagate the file name
	; defaults down the command line for user convenience.
	MOV	#FDB,R0			; Point to file FDB.
	ADD	#F.FNB,R0		; Point to filename block.
	MOV	#DEFNAM,R1		; Point to default filename block.
	MOV	N.FNAM(R0),N.FNAM(R1)	; Copy file name to default block.
	MOV	N.FNAM+2(R0),N.FNAM+2(R1)
	MOV	N.FNAM+4(R0),N.FNAM+4(R1)
	MOV	N.FTYP(R0),N.FTYP(R1)	; Copy file type.
	CLR	N.FVER(R1)		; Force default version 0.
	MOV	N.DVNM(R0),N.DVNM(R1)	; Copy device name.
	MOV	N.UNIT(R0),N.UNIT(R1)	; Copy unit no.
	JMP	REPEAT			; Get next file.

	.DSABL	LSB

EXITOK:	TTYMSG	<MAP -- Version V01.05 - 06-Jun-88.>,'0				; AB005
	TTYMSG	<Copyright (C) 1988 - XDT Computer Consultants. >,'$
	TTYMSG	<All Rights Reserved.>,'+

EXIT:	PUSH	#EX$SUC			; Exit with OK status.
	BR	QUIT			; Go away.
EXTNAK:	PUSH	#EX$SEV			; Exit with knackered status.
QUIT:	EXST$S	(SP)+			; Exit with status.

	.PAGE
	.SBTTL	GETMAP - Process the file name sitting in the FDB.

;+
;	-=< GETMAP >=-
;
; Purpose:	The file FDB has currently got a file name parsed into it by
;		CSI work. Use this information to look up the file ID, get the
;		file header(s) from INDEXF.SYS and then print the mapping
;		details for the user.
;
; Input:	-
;
; Output:	All registers disturbed.
;
;-

	.ENABL	LSB
GETMAP:					; Entry point.
	MOV	#FDB,R0			; Point to FDB.
	MOV	#FNB,R1			; Point R1 to file name block in FDB.
	MOV	#CSIBLK+C.DSDS,R2	; Point to dataset descriptor.
	MOV	#DEFNAM,R3		; Point to default file name block.
	JSR	PC,.PARSE		; Parse name into FNB.
	BCC	2$

	MOVB	F.ERR(R0),R1		; Get error code.
	BR	4$			; Go print error message.

2$:	; Now do a directory lookup on the name.
	QIOW$S	#IO.FNA,#FILLUN,#FILLUN,,#ISB,,<,,,,,#FNB> ; Find the file.
	CMPB	#IS.SUC,ISB		; Lookup OK ??
	BEQ	6$			; Yes - Br.

	MOVB	ISB,R1			; Get error code.
	CMPB	#IE.NSF,R1		; Is it "No Such File" ?
	BNE	4$			; No - Br.

	ERROR	<No such file.>,FATAL	; Yes - Say so then.

4$:	TTYNUM	<MAP -- *FATAL* -- File lookup error. Error code = >,R1,<.>
	JMP	EXTNAK			; Exit with bad status.

6$:	JSR	PC,GETNAM		; Go get the file name.

	; Now we have the file ID. Access INDEXF.SYS to get 1st header.
	QIOW$S	#IO.ACR,#FILLUN,#FILLUN,,#ISB,,<#INDEXF,,,,#100000> ;
	CMP	#IS.SUC,ISB		; Accessed OK ?
	BEQ	8$			; Yes - Br.

	MOVB	ISB,R1			; Get error code.
	TTYNUM	<MAP -- *FATAL* -- INDEXF.SYS lookup error. Error code = >,R1,<.>
	JMP	EXTNAK

8$:	; INDEXF.SYS is now accessed. Read the home block in.
	MOV	#BLOCK,R0		; Point to block buffer.
	QIOW$S	#IO.RVB,#FILLUN,#FILLUN,,#ISB,,<R0,#512.,,#0,#2> ; Read HOME block.
	MOV	#2,OFFSET		; Allow for boot and home block.
	ADD	H.IBSZ(R0),OFFSET	; Allow for index file bit map.

	JSR	PC,GETINF		; Go get the mapping info.

	QIOW$S	#IO.DAC,#FILLUN,#FILLUN,,#ISB,,<#INDEXF> ; Deaccess MFD
	RTS	PC

	.DSABL	LSB

	.PAGE
	.SBTTL	PRTMAP - Print the mapping information out.

;+
;	-=< PRTMAP >=-
;
; Purpose:	Take all of the mapping information gathered and print it out.
;
;-

	.ENABL	LSB

PRTMAP:					; Entry point.
	TTYMSG				; Print a blank line.
	TTYMSG	<Mapping information for . . . . . . . . . . : >,'$
	TTYOUT	#FILBUF			; Print the file name.

	BIT	#F.TWO4,FLAG		; Mapped by 2:4 pointers ??		; AB004
	BEQ	2$			; No - Br cos we handled it OK.		; AB004

	TTYMSG	<File is mapped by 2:4 pointers and MAP can't cope (yet!),>	; AB004
	JMP	8$			; Finished here.			; AB004

2$:	TTYMSG	<Space allocated (blocks)  . . . . . . . . . : >,'$
	PRTDBL	#FILSIZ			; Go print double word.
	TTYMSG	<.>,'+			; Terminate.

	BIT	#F.ZLEN,FLAG		; Is this a zero length file ??		; AB002
	BNE	8$			; Yes - Print no more for it then.	; AB002

	; Print the file traversal path length.					; AB003
	TTYMSG	<File traversal path length (blocks) . . . . : >,'$		; AB003
	PRTDBL	#TRVPTH								; AB003
	TTYMSG	<.>,'+								; AB003

	; Print out the header and pointer information.
	TTYMSG	<Headers  (minimum, actual, efficiency)  . . : >,'$
	PRTSNG	MINHED			; Print minimum needed.
	TTYMSG	<, >,0			; Separate.
	PRTSNG	NHEADS			; Print no. used.
	TTYMSG	<, >,0			; Separate.
	PERCNT	MINHED,NHEADS		; Print percentage efficiency.

	TTYMSG	<Pointers (minimum, actual, efficiency)  . . : >,'$
	PRTSNG	MINPNT			; Print minimum needed.
	TTYMSG	<, >,0			; Separate.
	PRTSNG	NPNTRS			; Print no. used.
	TTYMSG	<, >,0			; Separate.
	PERCNT	MINPNT,NPNTRS		; Print percentage efficiency.

	; Print out the contiguity information.
	TTYMSG	<Contiguity  . . . . . . . . . . . . . . . . : >,'$
	BIT	#F.LCNT,FLAG		; Is the file marked as contiguous ??
	BEQ	4$			; No - Br.

	TTYMSG	<Marked as contiguous.>,'+ ; File is marked as contiguous.
	BR	8$			; Br to quit.

4$:	CMP	NSEGS,#1		; Is the file splattered about ??
	BGT	6$			; Yes - Br.

	TTYMSG	<Placed contiguously.>,'+ ; Not splattered about at all.
	BR	8$			; Take common exit.

6$:	TTYMSG	<Discontiguous.>,'+	; It's splattered.

	TTYMSG	<File segments (number, smallest, largest) . : >,'$
	PRTSNG	NSEGS
	TTYMSG	<, >,0
	PRTDBL	#SEGMIN
	TTYMSG	<, >,0
	PRTDBL	#SEGMAX
	TTYMSG	<.>,'+

8$:	RTS	PC

	.DSABL	LSB

	.PAGE
	.SBTTL	GETNAM	- Get the file name.

;+
;	-=< GETNAM >=-
;
; Purpose:	Get the file name that we are analysing.
;
;-

	.ENABL	LSB
GETNAM:					; Entry point.
	PUSH	*			; Save all registers.
	MOV	#FNB,R5			; Point to file name block in FNB.
	MOV	#FILSTR,R0		; Point to output string.
	MOV	#FNBDEV,R2		; Assume device name in FNB.
	BIT	#NB.DEV,N.STAT(R5)	; Is it ??
	BEQ	2$			; Yes - Br to use FNB device name.
	MOV	#DSTDEV,R2		; No - Name in dataset

2$:	JSR	PC,(R2)			; Call the appropriate routine.

	MOV	#RDFUI,R2		; Assume need UFD from $$FSR2
	BIT	#NB.DIR,N.STAT(R5)	; Explicit UFD string in FNB ??
	BEQ	4$			; No - Use FSR one.

	MOV	#DSTUFD,R2		; Yes - Use that one.

4$:	JSR	PC,(R2)			; Call the appropriate routine.

	MOV	R5,R4			; Copy FNB pointer.
	ADD	#N.FNAM,R4		; Point to filename in FNB
	MOV	#3,R3			; Three RAD50 words to do.

6$:	MOV	(R4)+,R1		; Get RAD50 word.
	JSR	PC,$C5TA		; Convert to ASCII
	SOB	R3,6$			; Loop.

8$:	CMPB	#' ,-(R0)		; If space -
	BEQ	8$			; - strip it.

	INC	R0			; Point to next free character.
	MOVB	#'.,(R0)+		; Terminate name.
	MOV	N.FTYP(R5),R1		; Get file type.
	JSR	PC,$C5TA		; Convert to ASCII

10$:	CMPB	#' ,-(R0)		; If space -
	BEQ	10$			; - strip it.

	INC	R0			; Point to next free character.
	MOVB	#';,(R0)+		; Terminate type.

	MOV	N.FVER(R5),R1		; Get version no.
	CLR	R2			; No lead zeros
	JSR	PC,$CBOMG		; Convert to ASCII.
	MOV	R0,R1			; Copy end of string pointer.
	MOV	#FILSTR,R0		; Point to start of string.
	SUB	R0,R1			; Get length.
	MOVB	R1,FILBUF		; Load byte count.			; AB002
	POP	*			; Restore all registers.
	RTS	PC			; Done.

	.DSABL	LSB

	.PAGE
	.SBTTL	GETINF - Get the file's mapping info.

;+
;	-=< GETINF >=-
;
; Purpose:	Get the mapping statistics etc for this file.
;
;-

	.ENABL	LSB
GETINF:					; Entry point.
	CLR	NHEADS			; No headers counted yet.
	MOV	#F.RTV1!F.ZLEN,FLAG	; Initialise the FLAG word.		; AB001
	MOV	FID,R1			; Get file ID 1st word (INDEXF.SYS index).

2$:	; Read a header block for the file ID in FID. This may be the first
	; header or an extension header (R1=FID of header block to read).
	ADD	OFFSET,R1		; Offset over boot, home and bitmap blocks.
	MOV	#BLOCK,R5		; Point to file header block buffer.
	QIOW$S	#IO.RVB,#FILLUN,#FILLUN,,#ISB,,<R5,#1000,,#0,R1> ; Get 1st header.
	TST	NHEADS			; First header ??
	BNE	4$			; No - Skip the contig test then.

	BIT	#UC.CON,H.UCHA(R5)	; Yes - Is it marked as contiguous ?
	BEQ	4$			; No - Br then.

	BIS	#F.LCNTG,FLAG		; Yes - Remember that that's so.

4$:	; Process the header currently in the buffer.
	CLR	R4			; Prepare for BISB.
	BISB	H.MPOF(R5),R4		; Get word offset to map area.
	ASL	R4			; Get as byte offset.
	ADD	R5,R4			; Point to map area.
	MOV	R4,R5			; Point R5 to map area too.
	CMPB	#1,M.CTSZ(R5)		; Is this mapped by a 1:3 pointer ??	; AB004
	BEQ	6$			; Yes - Br.				; AB004

	BIS	#F.TWO4,FLAG		; No - Flag 2:4 pointer.		; AB004
	BR	10$			; And return to print info.		; AB004

6$:	CLR	R3			; Prepare for BISB.			; AB001
	BISB	M.USE(R5),R3		; Get no. of words of pointers.		; AB001
	BEQ	12$			; None - File is zero length.		; AB001

	ASR	R3			; Calculate no. of pointers.
	INC	NHEADS			; Count up this header.
	BIC	#F.ZLEN,FLAG		; Flag has finite length.		; AB001
	ADD	#M.RTRV,R5		; Point R5 to 1st pointer in the header.

8$:	JSR	PC,DOPNTR		; Process this pointer.
	ADD	#4,R5			; Point to next pointer.
	SOB	R3,8$			; Loop down the lot.

	MOV	M.EFNU(R4),R1		; Get pointer to extension header.
	BNE	2$			; If present go load that header.

10$:	; Finished processing all the headers for this file.
	; But we didn't add in the length of the last pointer to the
	; traversal path or worry about the last pointer being part
	; of the last segment.
	ADD	LSTCNT,TRVPTH+2		; Add the length of the last pointer	; AB003
	ADC	TRVPTH			; - into the traversal path.		; AB003
	JSR	PC,MAXMIN		; Process the last file segment.

12$:	JSR	PC,BEST			; Calculate the optimum mapping.
	RTS	PC

	.DSABL	LSB

	.PAGE
	.SBTTL	DOPNTR - Process a file mapping pointer.

;+
;	-=< DOPNTR >=-
;
; Purpose:	This routine is called for each retrieval pointer in use to map
;		the file. Each retrieval pointer can map up to 256 blocks. Files
;		which are not marked as contiguous may actually be placed
;		contiguously if their retrieval pointers map a contiguous area.
;		DOPNTR counts the number of individual file fragments remebering
;		the smallest and largest. It also calculates the file traversal
;		path. This is the sum of the geometric distance between each
;		area mapped by individual pointers. 
;
; Input:	R5	- Point to the retrieval pointer.
;
;-
	.ENABL	LSB

DOPNTR:					; Entry point.
	PUSH	*
	MOV	(R5),R0			; Get block count + hi lbn no.
	MOV	R0,R1			; Copy.
	CLRB	R1			; Leave block count in hi R1.
	SWAB	R1			; Get it to lo R1.
	INC	R1			; Add in the default block.
	BIC	#^C<377>,R0		; Clear off the block count byte.

	; R0	= hi order part of LBN for current pointer
	; 2(R5) = lo order part of LBN for current pointer
	; R1	= block count for current pointer
	BIT	#F.RTV1,FLAG		; Is this the very first pointer ??
	BEQ	2$			; No - Don't re-intialise then.

	; This is the first pointer for this file. Initialise for new file.
	CLR	NPNTRS			; No retrieval pointers counted yet.
	CLR	FILSIZ			; Zero the file size -			; AB001
	CLR	FILSIZ+2		; - double word.			; AB001
	CLR	TRVPTH			; Zero the file traversal -		; AB003
	CLR	TRVPTH+2		; - path double word.			; AB003
	CLR	SEGSIZ			; Initialise the segment size -
	CLR	SEGSIZ+2		; - accumulator double word.
	CLR	SEGMAX			; Initialise the maximum segment -
	CLR	SEGMAX+2		; - double word.
	MOV	#77777,SEGMIN		; Initialise the minimum segment -
	CLR	SEGMIN+2		; - double word (to a big +ve val.)
	MOV	#1,NSEGS		; All files are at least 1 segment long.
	MOV	R0,LSTLBN		; Initialise the previous pointer -	; AB005
	MOV	2(R5),LSTLBN+2		; - saved data to produce the 1st -	; AB005
	CLR	LSTCNT			; - pointer as the 1st segment.		; AB005

	.PAGE

2$:	; Process the current pointer.
	INC	NPNTRS			; Accumulate the no. of pointers.
	ADD	R1,FILSIZ+2		; Add the length mapped by this -
	ADC	FILSIZ			; - pointer into the file size.

	; See if the end of the area mapped by the previous pointer lies
	; contiguously with the front of the current one.
	MOV	LSTLBN,R4		; Get hi order previous lbn.
	MOV	LSTLBN+2,R3		; Get lo order previous lbn.
	ADD	LSTCNT,R3		; Add previous count to start lbn -	; AB005
	ADC	R4			; - from last pointer.

	CMPB	R0,R4			; High orders lbns match ??
	BNE	4$			; No - Br & count discontig. segment.

	CMP	2(R5),R3		; Yes - Low orders match ??
	BEQ	6$			; Yes - Contiguous with last pointer.

4$:	; This segment is discontiguous from the last one.
	INC	NSEGS			; Count a discontiguity.
	JSR	PC,MAXMIN		; Do the max and min test.
	CLR	SEGSIZ			; Zero the saved -
	CLR	SEGSIZ+2		; - segment size.

6$:	ADD	R1,SEGSIZ+2		; Add this one into the -
	ADC	SEGSIZ			; - segment size double word.

	BIT	#F.RTV1,FLAG		; Looking at the very 1st pointer ??
	BNE	10$			; Yes - Skip rest of stats for 1st one.

	; Accumulate the file traversal path length.				; AB003
	MOV	R0,R3			; Copy hi order lbn.			; AB003
	MOV	2(R5),R4		; Copy lo order lbn.			; AB003
	SUB	LSTLBN+2,R4		; Get distance between -		; AB003
	SBC	R3			; - last one -				; AB003
	SUB	LSTLBN,R3		; - and this one.			; AB003
	BGE	8$			; Br if its +ve.			; AB003

	NEG	R3			; Get it as -				; AB003
	NEG	R4			; - ABS distance -			; AB003
	SBC	R3			; - in double word.			; AB003

8$:	ADD	R4,TRVPTH+2		; Accumulate it into -			; AB003
	ADC	TRVPTH			; - traversal path -			; AB003
	ADD	R3,TRVPTH		; - length double word.			; AB003

10$:	; Finished processing this pointer - Save it for the next DOPNTR call.
	MOV	R0,LSTLBN		; Save the current lbn - 
	MOV	2(R5),LSTLBN+2		; - pointer.
	MOV	R1,LSTCNT		; Save current block count.
	BIC	#F.RTV1,FLAG		; Not looking at the first one now.
	POP	*			; Restore all registers.
	RTS	PC			; Finished.	

	.DSABL	LSB

	.PAGE
	.SBTTL	MAXMIN - Check for the current segment being largest/smallest.

;+
;	-=< MAXMIN >=-
;
; Purpose:	Check to see if the current segment is larger than the current
;		maximum or smaller than the current smallest.
;
; Input:	SEGSIZ	- Size of current segment.
;
; Output:	SEGMIN,SEGMAX conditionally updated.
;		All registers preserved.
;
;-

MAXMIN:
	CMP	SEGSIZ,SEGMAX		; Bigger than curent biggest ??
	BLO	4$			; No - Go test MIN.
	BHI	2$			; Yes - Br.

	; High orders are equal.
	CMP	SEGSIZ+2,SEGMAX+2	; Maybe - Is it ??	
	BLOS	4$			; No - Br to do min. test.

2$:	MOV	SEGSIZ,SEGMAX		; Yes - Remember -
	MOV	SEGSIZ+2,SEGMAX+2	; - it for now.

4$:	CMP	SEGSIZ,SEGMIN		; Smaller than current smallest ?
	BHI	8$			; No - Br to quit.
	BLO	6$			; Yes - Br to remember it then.

	; High orders are equal.
	CMP	SEGSIZ+2,SEGMIN+2	; Maybe - Is it ??
	BHIS	8$			; No - Br to quit.

6$:	MOV	SEGSIZ,SEGMIN		; Yes - Remember -
	MOV	SEGSIZ+2,SEGMIN+2	; - it for now.

8$:	RTS	PC			; Finished.

	.PAGE
	.SBTTL	BEST - Calculate and display the best mapping achievable.

;+
;	-=< BEST >=-
;
; Purpose:	Calculate the best mapping possible based on the file size
;		and calculate the mapping efficiency. Print out the information.
;
; Input:	FILSIZ	- contains the file size in blocks.
;		NHEADS	- No. of headers actually used.
;		NPNTRS	- No. of pointers actually used.
;		NSEGS	- No. of contiguous file segments.
;
; Note:	1)	Each header has 102 pointers each mapping 256. blocks.
;		This gives a max. of 26112 blocks per pointer.
;
;-

	.ENABL	LSB
BEST:					; Entry point.
	BIT	#F.ZLEN,FLAG		; Is this a zero length file ??
	BNE	6$			; Yes - Skip best mapping calculation.

	MOV	FILSIZ,R2		; Get file size -
	MOV	FILSIZ+2,R3		; - double word.
	CLR	R1			; Zero the counter.

2$:	INC	R1			; Count a header.
	SUB	#26112.,R3		; Calculate no. of headers.
	SBC	R2			; -
	BPL	2$			; If some left go round again.

	MOV	R1,MINHED		; Save min. no. of headers.

	CLR	R1			; Zero the pointer counter.
	MOV	FILSIZ,R2		; Get file size -
	MOV	FILSIZ+2,R3		; - double word.
	PUSH	R3			; Get low order part.
	BIC	#177400,(SP)+		; Odd piece over ??
	BEQ	4$			; No - Br.

	INC	R1			; Yes - Count up this one.

4$:	ASHC	#-10,R2			; Divide by pointer size.
	ADD	R3,R1			; Add them in.
	MOV	R1,MINPNT		; Save number of pointers.

6$:	RTS	PC			; Finished here for now.

	.DSABL	LSB

	.PAGE
	.SBTTL	PRTDBL & PRTSNG - Print out a double or single precision word.

;+
;	-=< PRTDBL & PRTSNG >=-
;
; Purpose:	Print out a double or single precision word on TI: without
;		any VFC in decimal.
;
; Input:	PRTDBL - R1 - Points to double word pair.
;		PRTSNG - R1 - Contains value to print.
;
; Output:	R1	- destroyed.
;		All others saved.
;
;-

	.ENABL	LSB
PRTDBL:					; Entry point.
	PUSH	<R0,R2,#$CDDMG>		; Save regs. and set conversion routine.
	BR	2$			; Join common routine.

PRTSNG:					; Entry point
	PUSH	<R0,R2,#$CBDMG>		; Save regs. and set conversion routine.

2$:	MOV	#ASCBUF,R0		; Point to print buffer.
	CLR	R2			; No lead zeros.
	JSR	PC,@(SP)+		; Convert it.	
	MOV	R0,R1			; Copy free character pointer.
	MOV	#ASCBUF,R0		; Point to print buffer.
	SUB	R0,R1			; Calculate no. of characters to print.
	TTYOU1	R0,R1,#0		; Print it.
	POP	<R2,R0>			; Restore registers.
	RTS	PC

	.DSABL	LSB

	.PAGE
	.SBTTL	PERCNT - Print a value as a precentage.

;+
;	-=< PERCNT >=-
;
; Purpose:	Print up the two input values as percentage.
;
; Input:	R2	- dividend
;		R1	- divisor
;
; Output:	All registers saved.
;
;-

	.ENABL	LSB
PERCNT:					; Entry point.
	PUSH	*			; Save all registers.
	MUL	#1000.,R2		; Get as - 
	DIV	R1,R2			; - % * 10.
	TST	R3			; Any remainder ??
	BEQ	2$			; No - No round up then.

	ASR	R1			; Get divisor / 2.
	CMP	R3,R1			; Round up result ??
	BLE	2$			; No - Br.

	INC	R2			; Yes - Round up.

2$:	MOV	R2,R1			; Get to where $CBDMG wants it.
	MOV	#ASCBUF,R0		; Point to output buffer.
	CLR	R2			; No lead zeros.
	JSR	PC,$CBDMG		; Convert to ASCII.
	MOVB	-(R0),R1		; Strip of the last character.
	CMPB	#'0,R1			; Was it a trailing '0' ??
	BEQ	4$			; Yes - Strip it off then.

	MOVB	#'.,(R0)+		; Insert the decimal point.
	MOVB	R1,(R0)+		; Insert the fraction.

4$:	MOVB	#'%,(R0)+		; Load % sign.
	MOV	R0,R1			; Copy EOS pointer.
	MOV	#ASCBUF,R0		; Point to output buffer.
	SUB	R0,R1			; Calculate length of string.
	TTYOU1	R0,R1,#'+		; Print it.
	POP	*			; Restore registers.
	RTS	PC			; Done.

	.DSABL	LSB

	.PAGE
	.SBTTL	File name routines

;+
;	-=< FNBDEV >=-
;
; Purpose:	Extract device name from FNB where it was loaded from the
;		command line.
;
;-

FNBDEV:					; Entry point
	MOVB	N.DVNM(R5),(R0)+	; Copy 1st device name char.
	MOVB	N.DVNM+1(R5),(R0)+	; Copy 2nd device name char.
	MOV	N.UNIT(R5),R1		; Get unit no.
	BNE	2$			; Br if non-zero.

	MOVB	#'0,(R0)+		; Load in a zero.
	BR	4$			; Go quit.

2$:	CLR	R2			; No lead zeros.
	JSR	PC,$CBOMG		; Convert to ASCII

4$:	MOVB	#':,(R0)+		; Terminate the device string.
	RTS	PC

;+
;	-=< DSTDEV >=-
;
; Purpose:	Get device name from dataset descriptor.
;
;-

DSTDEV:					; Entry point.
	MOV	R5,R1			; Copy FNB pointer.
	SUB	#F.FNB,R1		; Point back to FDB.
	MOV	F.DSPT(R1),R1		; Get dataset descriptor address.
	MOV	(R1)+,R2		; Get length of string.
	MOV	(R1),R1			; Get string address.

2$:	MOVB	(R1)+,(R0)+		; Copy it.
	SOB	R2,2$			; Loop.

	MOVB	#':,(R0)+		; Terminate the device string.
	RTS	PC

	.PAGE
	.SBTTL	RDFUI	- Read default directory string from $$FSR2.

;+
;	-=< RDFUI >=-
;
; Purpose:	Read the default UFD from $$FSR2. This routine has to worry
;		about the situation where we might be running under RSX-11M-PLUS
;		with named directories turned on.
;
;-

	.MCALL	GDIR$S
	.PSECT	XDTRWD	RW,D,LCL,REL,CON

DSTRLN:	.WORD	0			; Length of returned string.

	.PSECT	XDTROC	I,RO,LCL,REL,CON

RDFUI:					; Entry point.
	GDIR$S	#0,R0,#11.,#DSTRLN	; Try to get default directory string.
	BCS	2$			; Br if failed (Its 11M!)

	CMPB	#'],1(R0)		; M-PLUS in NONAMED mode ??
	BEQ	2$			; Yes - Br.

	ADD	DSTRLN,R0		; No - Space R0 over the name string.
	BR	4$			; Finished.

2$:	; This is M-PLUS in NONAMED and 11M in its only mode.
	MOVB	#'[,(R0)+		; Start of UFD string.
	JSR	PC,.RDFUI		; Call FCS for default UFD.
	PUSH	R1			; Save UFD.
	SWAB	R1			; Get group in low byte.
	CLR	R2			; No lead zeros.
	JSR	PC,$CBTMG		; Convert to ASCII
	MOVB	#',,(R0)+		; Separator.
	POP	R1			; Get UFD back.
	CLR	R2			; No lead zeros.
	JSR	PC,$CBTMG		; Convert member half.
	MOVB	#'],(R0)+		; Terminate it.

4$:	RTS	PC

;+
;	-=< DSTUFD >=-
;
; Purpose:	Get UFD from dataset descriptor.
;
;-

DSTUFD:					; Entry point.
	MOV	R5,R1			; Copy FNB pointer.
	SUB	#F.FNB,R1		; Point back to FDB.
	MOV	F.DSPT(R1),R1		; Get dataset descriptor address.
	MOV	4(R1),R2		; Get length of UFD string.
	MOV	6(R1),R1		; Get UFD string address.
2$:	MOVB	(R1)+,(R0)+		; Copy it.
	SOB	R2,2$			; Loop.
	RTS	PC

	.END	MAP
