	.TITLE	CONTIGUIZE - COPY A FILE AND MAKE IT CONTIGUOUS
	.IDENT	/1.8/
;
;	AUTHOR:	ROGER JENKINS
;	DATE:	10/8/85
;


;*****************************************************************
;
; RABS AND FABS
;
;*****************************************************************

	.PSECT	FABS,WRT,NOEXE,LONG

;*****************************************************************
;
; INPUT FILE CONTROL BLOCKS
;
;*****************************************************************

INFAB:	$FAB	FAC=<BIO GET>,-
		NAM=INNAM

INRAB:	$RAB	BKT=0,-
		FAB=INFAB,-
		MBC=51,-
		ROP=<BIO LOC>,-
		UBF=IO_BUF,-
		USZ=BUF_SIZE

INNAM:	$NAM	ESA=EXPANDED_FILE_SPEC,-
		ESS=255,-
		RSA=EXPANDED_FILE_SPEC,-
		RSS=255

EXPANDED_FILE_SPEC:			; EXPANDED FILE SPEC WILL BE PLACED HERE
		.BLKB	255

;*****************************************************************
;
; OUTPUT FILE ACCESS BLOCK (FAB) AND RECORD ACCESS BLOCK (RAB)
;
;*****************************************************************

	.ALIGN	LONG

OUTFAB:	$FAB	FAC=<BIO PUT>,-
		FOP=<CTG MXV>

OUTRAB:	$RAB	BKT=0,-
		FAB=OUTFAB,-
		RBF=IO_BUF,-
		ROP=<BIO>


;*****************************************************************
;
; PARSER DATA
;
;*****************************************************************

	.PSECT
	$TPADEF					; PARSER OFFSETS

LF = 10						; LINE FEED CHARACTER

ALLOCATE_VALUE:
	.BLKL	1				; NUMBER OF BLOCKS TO ALLOCATE

SHOW_FLAG:
	.LONG	0				; 1 IF SHOW SWITCH PRESENT

INPUT_FILE_DESCR:
	.QUAD	0				; DESCRIPTOR OF INPUT FILE

OUTPUT_FILE_DESCR:
	.QUAD	0				; DESCRIPTOR OF OUTPUT FILE

ARG_BLK:
	.LONG	TPA$K_COUNT0			; LENGTH OF TABLE IN LONG WORDS
	.LONG	TPA$V_ABBRFM			; ALLOW KEYWORD ABBREVIATIONS
CMD_LEN: .BLKL	1				; LENGTH OF CMD IN CMD_LINE
	.ADDRESS CMD_LINE			; COMMAND LINE ADDRESS
	.BLKB	TPA$K_LENGTH0-16		; REST OF BLOCK



;*****************************************************************
;
; PARSER STATE TABLE
;
;*****************************************************************


	$INIT_STATE STATE_TABLE,KEY_TABLE
;
; START SWITCHES AND/OR INPUT FILE SPEC
;
	$STATE	START
	$TRAN	TPA$_BLANK,START
	$TRAN	'/',SWITCH_NAME
	$TRAN	TPA$_LAMBDA,INPUT_FILE

	$STATE	SWITCH_NAME
	$TRAN	'ALLOCATE',ALLOCATE_SWITCH
	$TRAN	'SHOW_COUNT',START,,1,SHOW_FLAG

	$STATE	ALLOCATE_SWITCH
	$TRAN	'='

	$STATE
	$TRAN	TPA$_DECIMAL,START,,,ALLOCATE_VALUE
;
; PARSE INPUT FILE NAME
;
	$STATE	INPUT_FILE
	$TRAN	TPA$_FILESPEC,,,,INPUT_FILE_DESCR
;
; PARSE OUTPUT FILE NAME

	$STATE
	$TRAN	TPA$_FILESPEC,,,,OUTPUT_FILE_DESCR
	$TRAN	TPA$_EOS,TPA$_EXIT

	$END_STATE


;*****************************************************************
;
; OTHER DATA
;
;*****************************************************************


BUF_SIZE = 512*127				; LARGEST NUMBER OF BLOCKS WE CAN XFR
IO_BUF:	.BLKB	BUF_SIZE			; I/O BUFFER

SIZE_GOAL:					; DESIRED SIZE OF OUTPUT FILE
	.BLKL	1
CUR_SIZE:					; CURRENT SIZE
	.LONG	0
CONTIG_SIZE:					; LARGEST CONTIGUOUS PEICE OF DISK
	.BLKL	1

EXT_NUM:					; CURRENT EXTENT NUMBER
	.LONG	0

BLOCKS_COPIED:					; NUMBER OF BLOCKS COPIED
	.LONG	0

CMD_LINE_DESCR:					; DESCR OF BLANK COMMAND LINE
	.LONG	256
	.ADDRESS CMD_LINE
CMD_LINE:					; CMD LINE BUFFER
	.BLKB	256

DISK:	.LONG	0				; DISK NAME DESCR
	.ADDRESS EXPANDED_FILE_SPEC

PROMPT:	.ASCID	"File:  "			; PROMPT TEXT

PROMPT_FLAG:					; TO PROMPT OR NOT TO PROMPT
	.BLKL	1

SYNTAX_ERROR:
	.ASCID	"***** Command line syntax error *****"

NO_INPUT_FILE_MSG:
	.ASCID	"***** No input file specified on command line *****"

ALQ_MSG:
	.ASCID	<LF>"File allocation beginning..."

EXT_CTL:
	.ASCID	"Extent # !UL contains !UL block!%S, total size: !UL block!%S"

COPY_MSG:
	.ASCID	<LF>"File copy beginning..."

COPY_CTL:
	.ASCID	"!6UL block!%S copied"

DONE_MSG:
	.ASCID	"All Done!!"

BIGCONTIG_ERR_MSG:
	.ASCID	<LF>"Error occured while allocating space:"

FAO_BUF_DESCR:					; DESCRIPTION OF EMPTY BUFFER
	.LONG	80
	.ADDRESS FAO_BUF
FAO_BUF:					; BUFFER USED BY FAO
	.BLKB	80

FORMATTED_BUF_DESCR:				; DESC OF FORMATTED BUFFER
	.BLKL	1
	.ADDRESS FAO_BUF



;*****************************************************************
;
; CODE
;
;*****************************************************************

	.ENTRY	CONTIGUIZE,^M<>

;*****************************************************************
;
; GET FILE NAME FROM EITHER COMMAND LINE OR PROMPT
;
;*****************************************************************

PROMPT_AGAIN:
	PUSHAL	PROMPT_FLAG
	PUSHAL	CMD_LEN
	PUSHAQ	PROMPT
	PUSHAQ	CMD_LINE_DESCR
	CALLS	#4,G^LIB$GET_FOREIGN

	BLBS	R0,GOT_COMMAND
	CMPL	R0,#RMS$_EOF			; ^Z?
	BNEQ	GET_CMD_ERROR			; NO
	BRW	DONE				; YES - EXIT

GET_CMD_ERROR:
	PUSHL	R0				; NO - PUSH ERORR STATUS
	CALLS	#1,G^LIB$SIGNAL			; PRINT ERROR MESSAGE
	BRW	DONE				; EXIT

GOT_COMMAND:


;*****************************************************************
;
; PARSE COMMAND LINE
;
;*****************************************************************

	PUSHAL	KEY_TABLE
	PUSHAL	STATE_TABLE
	PUSHAL	ARG_BLK
	CALLS	#3,G^LIB$TPARSE			; PARSE COMMAND LINE

	BLBS	R0,CHECK_PARSE			; CMD LINE PARSED OK
	MOVAQ	SYNTAX_ERROR,R1			; ADR OF ERROR MESSAGE
	BRW	PARSE_ERROR			; CMD LINE HAD SYNTAX ERROR


;*****************************************************************
;
; SEE IF RESULTS OF THE PARSE ARE OK.
; SET UP POINTERS FOR OUTPUT FILE NAME.
;
;*****************************************************************

CHECK_PARSE:
	TSTL	INPUT_FILE_DESCR+4		; IS DESCRIPTOR ADDRESS ZERO?
	BNEQ	GOT_INPUT_FILE			; NO - ALL IS WELL
	MOVAQ	NO_INPUT_FILE_MSG,R1		; GET ADDRESS OF ERROR MSG
	BRW	PARSE_ERROR			; WRITE ERROR MESSAGE

GOT_INPUT_FILE:
	MOVL	INPUT_FILE_DESCR+4,INFAB+FAB$L_FNA   ; PUT FILE NAME ADR IN FAB
	CVTWB	INPUT_FILE_DESCR,INFAB+FAB$B_FNS     ; PUT FILE NAME LEN IN FAB

	MOVL	INPUT_FILE_DESCR+4,OUTFAB+FAB$L_DNA  ; PUT FILE NAME ADR IN FAB
	CVTWB	INPUT_FILE_DESCR,OUTFAB+FAB$B_DNS    ; PUT FILE NAME LEN IN FAB
	TSTL	OUTPUT_FILE_DESCR		; IS DESCRIPTOR ADDRESS ZERO?
	BEQL	NO_OUTPUT_FILE			; YES - USE INPUT AS DEFAULT
	MOVL	OUTPUT_FILE_DESCR+4,OUTFAB+FAB$L_FNA ; PUT FILE NAME ADR IN FAB
	CVTWB	OUTPUT_FILE_DESCR,OUTFAB+FAB$B_FNS   ; PUT FILE NAME LEN IN FAB

NO_OUTPUT_FILE:


;*****************************************************************
;
; OPEN AND CONNECT TO INPUT FILE.
;
;*****************************************************************

	$OPEN	FAB=INFAB			; OPEN INPUT FILE
	BLBS	R0,CON_IN			; OK
	BRW	IN_FAB_ERROR			; ERROR

CON_IN:
	$CONNECT RAB=INRAB			; CONNECT RECORD STREAM
	BLBS	R0,FAB_COPY			; OK
	BRW	IN_RAB_ERROR			; ERROR


;*****************************************************************
;
; BUILD DISK DESCRIPTOR FROM INNAM.
; MOVE VALUES INTO OUTFAB.  MOST COME FROM INFAB, BUT ALLOCATION
; QUANTITY WILL COME FROM COMMAND LINE IF /ALLOCATE=<SIZE> WAS
; SPECIFIED.
;*****************************************************************

FAB_COPY:
	MOVB	INNAM+NAM$B_ESL,DISK			; ASSUME ESL FOR NOW
	TSTB	INNAM+NAM$B_RSL				; IS RSL THE ONE TO USE?
	BEQL	NOT_RSL					; NO - KEEP WHAT WE GOT
	MOVB	INNAM+NAM$B_RSL,DISK			; YES - USE RSL
NOT_RSL:

	MOVL	INFAB+FAB$L_ALQ,SIZE_GOAL		; FILE SIZE
	TSTL	ALLOCATE_VALUE				; ALQ FROM CMD LINE?
	BEQL	NO_ALQ_VALUE				; NO
	MOVL	ALLOCATE_VALUE,SIZE_GOAL		; YES - PUT IT IN FAB

NO_ALQ_VALUE:
	MOVB	INFAB+FAB$B_BKS,OUTFAB+FAB$B_BKS	; BUCKET SIZE
	MOVW	INFAB+FAB$W_DEQ,OUTFAB+FAB$W_DEQ	; DEFAULT EXTEND SIZE
	MOVB	INFAB+FAB$B_FSZ,OUTFAB+FAB$B_FSZ	; FIXED CTRL AREA SIZE
	MOVW	INFAB+FAB$W_GBC,OUTFAB+FAB$W_GBC	; GLOBAL BUFFER COUNT
	MOVL	INFAB+FAB$L_MRN,OUTFAB+FAB$L_MRN	; MAX RECORD NUMBER
	MOVW	INFAB+FAB$W_MRS,OUTFAB+FAB$W_MRS	; MAX RECORD SIZE
	MOVB	INFAB+FAB$B_ORG,OUTFAB+FAB$B_ORG	; FILE ORGANIZATION
	MOVB	INFAB+FAB$B_RAT,OUTFAB+FAB$B_RAT	; RECORD ATTRIBUTES
	MOVB	INFAB+FAB$B_RFM,OUTFAB+FAB$B_RFM	; RECORD FORMAT


;*****************************************************************
;
; PRINT STARTING MESSAGE
; FIND OUT SIZE OF LARGEST CONTIGUOUS PIECE 
; MOVE SIZE INTO FAB
;
;*****************************************************************

	TSTL	SHOW_FLAG			; DO THEY WANT TO SEE MESSAGES?
	BEQL	NO_SHOW_ALQ			; NO, SO DON'T PRINT THEM
	PUSHAQ	ALQ_MSG				; "STARTING ALLOCATION" MESSAGE
	CALLS	#1,G^LIB$PUT_OUTPUT		; PRINT IT

NO_SHOW_ALQ:
	PUSHAL	CONTIG_SIZE			; RETURN BIGGEST CONTIG PIECE HERE
	PUSHAQ	DISK				; DISK WHERE OUTPUT FILE WILL BE PLACED
	CALLS	#2,BIGCONTIG			; FIND LARGEST CONTIGOUS PIECE

	BLBS	R0,NO_CREATE_ALQ_ERROR		; NO ERROR FROM BIGCONTIG
	BRW	BIGCONTIG_ERROR			; ERROR FROM BIGCONTIG

NO_CREATE_ALQ_ERROR:
	MOVL	CONTIG_SIZE,OUTFAB+FAB$L_ALQ	; MAKE FAB SIZE = BIG PIECE
	CMPL	CONTIG_SIZE,SIZE_GOAL		; IS CONTIGUOUS PIECE TOO BIG?
	BLEQ	CREATE				; NO - OK TO CREATE
	MOVL	SIZE_GOAL,OUTFAB+FAB$L_ALQ	; YES - ONLY USE WHAT WE NEED


;*****************************************************************
;
; CREATE OUTPUT FILE
;
;*****************************************************************

CREATE:
	$CREATE	FAB=OUTFAB			; OPEN OUTPUT FILE
	BLBS	R0,CON_OUT			; NO ERRORS
	BRW	OUT_FAB_ERROR			; ERROR

CON_OUT:
	$CONNECT RAB=OUTRAB			; CONNECT TO RECORD STREAM
	BLBS	R0,EXTEND_PREP			; NO ERRORS
	BRW	OUT_RAB_ERROR			; ERROR


;*****************************************************************
;
; EXTEND FILE UNTIL IT REACHES ITS DESIRED SIZE
;
;*****************************************************************

EXTEND_PREP:
	ADDL2	OUTFAB+FAB$L_ALQ,CUR_SIZE	; COMPUTE CURRENT FILE SIZE

	TSTL	SHOW_FLAG			; DO THEY WANT TO SEE MESSAGES?
	BEQL	NO_SHOW_EXT			; NO, SO DON'T PRINT THEM
	INCL	EXT_NUM				; COUNT THIS EXTENT

	$FAO_S	CTRSTR=EXT_CTL,-		; FORMAT EXTEND MESSAGE
		OUTLEN=FORMATTED_BUF_DESCR,-
		OUTBUF=FAO_BUF_DESCR,-
		P1=EXT_NUM,-
		P2=OUTFAB+FAB$L_ALQ,-
		P3=CUR_SIZE

	PUSHAQ	FORMATTED_BUF_DESCR		; ADR OF LINE TO BE PRINTED
	CALLS	#1,G^LIB$PUT_OUTPUT		; WRITE OUTPUT
NO_SHOW_EXT:

	CMPL	CUR_SIZE,SIZE_GOAL		; HAVE WE REACHED OUR DESIRED SIZE?
	BGEQ	COPY_BLOCK			; YES - START COPYING BLOCKS

	PUSHAL	CONTIG_SIZE			; LARGEST CONTIGUOUS PIECE
	PUSHAL	DISK				; DISK CONTAINING OUTPUT FILE
	CALLS	#2,BIGCONTIG			; FIND LARGEST CONTIGOUS PIECE

	BLBS	R0,NO_EXT_ALQ_ERROR		; NO ERROR FROM BIGCONTIG
	BRW	BIGCONTIG_ERROR			; ERROR FROM BIGCONTIG

NO_EXT_ALQ_ERROR:
	MOVL	CONTIG_SIZE,OUTFAB+FAB$L_ALQ	; GET ALL OF THE CONTIG SPACE 
	ADDL3	CONTIG_SIZE,CUR_SIZE,R9		; COMPUTE TOTAL FILE SIZE
	CMPL	R9,SIZE_GOAL			; WILL IT BE TOO BIG?
	BLEQ	EXTEND				; NO - OK TO EXTEND
	SUBL3	CUR_SIZE,SIZE_GOAL,OUTFAB+FAB$L_ALQ	; YES - ONLY USE WHAT WE NEED

EXTEND:
	$EXTEND	FAB=OUTFAB			; EXTEND THE FILE
	BRW	EXTEND_PREP			; GO BACK AND SEE IF WE NEED MORE


;*****************************************************************
;
; COPY BLOCK BY BLOCK
;
;*****************************************************************

COPY_BLOCK:
	TSTL	SHOW_FLAG			; DO THEY WANT TO SEE MESSAGES?
	BEQL	COPY_NEXT_BLOCK			; NO, SO DON'T PRINT THEM
	PUSHAQ	COPY_MSG			; COPY STARTING MESSAGE
	CALLS	#1,G^LIB$PUT_OUTPUT		; PRINT MESSAGE

;*****************************************************************
;
; READ A BUFFER OF DATA
;
;*****************************************************************

COPY_NEXT_BLOCK:
	$READ	RAB=INRAB			; READ A BLOCK
	BLBS	R0,WRITE			; READ WAS OK
	CMPL	R0,#RMS$_EOF			; EOF?
	BEQL	DONE				; YES - STOP
	BRW	IN_RAB_ERROR			; AN ERROR OCCURED


;*****************************************************************
;
; WRITE BUFFER OF DATA
;
;*****************************************************************

WRITE:
	MOVW	INRAB+RAB$W_RSZ,OUTRAB+RAB$W_RSZ   ; MOVE REC SIZE TO OUTRAB
	$WRITE	RAB=OUTRAB			; WRITE BLOCK
	BLBS	R0,NO_WRITE_ERROR		; NO ERROR
	BRW	OUT_RAB_ERROR			; ERROR - GO TO ERROR SECTION


;*****************************************************************
;
; SEE IF WE PRINT NUMBER OF BLOCKS COPIED,
; COMPUTE NUMBER OF BLOCKS COPIED
; FORMAT AND PRINT MESSAGE
; GO BACK FOR MORE
;
;*****************************************************************

NO_WRITE_ERROR:
	TSTL	SHOW_FLAG			; DO THEY WANT TO SEE MESSAGES?
	BEQL	NO_SHOW_COPY_BLOCK		; NO, SO DON'T PRINT THEM

	MOVZWL	INRAB+RAB$W_RSZ,R9		; GET NUMBER OF BYTES READ
	DIVL2	#512,R9				; CONVERT BYTES TO BLOCKS
	ADDL2	R9,BLOCKS_COPIED		; COUNT TOTAL BLOCKS COPIED

	$FAO_S	CTRSTR=COPY_CTL,-		; FORMAT COPY MESSAGE
		OUTLEN=FORMATTED_BUF_DESCR,-
		OUTBUF=FAO_BUF_DESCR,-
		P1=BLOCKS_COPIED

	PUSHAQ	FORMATTED_BUF_DESCR		; ADR OF LINE TO BE PRINTED
	CALLS	#1,G^LIB$PUT_OUTPUT		; WRITE OUTPUT
NO_SHOW_COPY_BLOCK:

	BRW	COPY_NEXT_BLOCK			; COPY ANOTHER MOUTHFULL


;*****************************************************************
;
; WRAP THINGS UP
;
;*****************************************************************

DONE:
	TSTL	SHOW_FLAG			; DO THEY WANT TO SEE MESSAGES?
	BEQL	NO_SHOW_DONE			; NO, SO DON'T PRINT THEM

	PUSHAQ	DONE_MSG			; ADR OF DONE MESSAGE
	CALLS	#1,G^LIB$PUT_OUTPUT		; WRITE OUTPUT

NO_SHOW_DONE:
	$CLOSE	FAB=INFAB			; CLOSE INPUT FILE
	$CLOSE	FAB=OUTFAB			; CLOSE OUTPUT FILE
	BRB	EXIT

;*****************************************************************
;
; ERROR PROCESSING
;
;*****************************************************************

IN_FAB_ERROR:
	MOVL	INFAB+FAB$L_STS,R2		; ERROR STATUS CODE
	MOVL	INFAB+FAB$L_STV,R3		; ERROR STATUS VECTOR
	BRB	WRITE_IO_ERROR_MSG		; NOW WRITE ERROR MESSAGE

IN_RAB_ERROR:
	MOVL	INRAB+RAB$L_STS,R2		; ERROR STATUS CODE
	MOVL	INRAB+RAB$L_STV,R3		; ERROR STATUS VECTOR
	BRB	WRITE_IO_ERROR_MSG		; NOW WRITE ERROR MESSAGE

OUT_FAB_ERROR:
	MOVL	OUTFAB+FAB$L_STS,R2		; ERROR STATUS CODE
	MOVL	OUTFAB+FAB$L_STV,R3		; ERROR STATUS VECTOR
	BRB	WRITE_IO_ERROR_MSG		; NOW WRITE ERROR MESSAGE

OUT_RAB_ERROR:
	MOVL	OUTRAB+RAB$L_STS,R2		; ERROR STATUS CODE
	MOVL	OUTRAB+RAB$L_STV,R3		; ERROR STATUS VECTOR
	BRB	WRITE_IO_ERROR_MSG		; NOW WRITE ERROR MESSAGE

WRITE_IO_ERROR_MSG:
	PUSHL	R3				; PUSH STATUS VECTOR ONTO STACK
	PUSHL	R2				; PUSH STATUS CODE ONTO STACK
	CALLS	#2,G^LIB$SIGNAL			; WRITE ERROR MESSAGE
	BRB	EXIT				; RETURN TO CALLER

PARSE_ERROR:
	PUSHL	R1				; ADR OF ERROR MESSAGE DESCRIPTOR
	CALLS	#1,G^LIB$PUT_OUTPUT		; WRITE ERROR MESSAGE
	BRB	EXIT				; RETURN TO CALLER

BIGCONTIG_ERROR:
	PUSHL	R0				; SAVE ERROR CODE FOR LIB$SIGNAL
	PUSHAL	BIGCONTIG_ERR_MSG		; MESSAGE ADR FOR LIB$PUT_OUTPUT
	CALLS	#1,G^LIB$PUT_OUTPUT		; SAY ERROR IS FROM BIGCONTIG
	CALLS	#1,G^LIB$SIGNAL			; WRITE ERROR MESSAGE
	BRB	EXIT				; RETURN TO CALLER

EXIT:
	RET					; RETURN TO CALLER (VMS) WITH STATUS

	.END	CONTIGUIZE
