Google
 

Trailing-Edge - PDP-10 Archives - AP-D471B-SB_1978 - fileio.bli
There are 12 other files named fileio.bli in the archive. Click here to see a list.
!***COPYRIGHT (C) 1974, 1975, 1976, 1977 DIGITAL EQUIPMENT CORP., MAYNARD, MASS.***
%%
%
	THIS MODULE CONTAINS ALL THE FILE I/O ROUTINES.

	GETFIL - GIVEN FILE SPEC, DOES OPEN, LOOKUP/ENTER, INBUF/OUTBUF, RETURNS CHANNEL
	INBYT  - READS FROM SPECIFIED INPUT FILE
	OTBYT  - WRITES TO SPECIFIED OUTPUT FILE
	CLOFIL - CLOSES A FILE
	RESET  - DOES RESET UUO
	BUFSIZ - GETS BUFFER SIZE FOR GIVEN DEVICE
	GETBUF - GETS SPECIFIED NUMBER OF BUFFERS

%
%%

MODULE FILEIO (MLIST,FSAVE,TIMER=EXTERNAL(SIX12)) =
BEGIN
	! BINDS FOR CREATING I/O UUO'S
	BIND	OPEN = #50,	IN = #56,	OUT = #57,
		STATZ = #63,	CLOSE = #70,	RELEASE = #71,
		LOOKUP = #76,	ENTER = #77,	INBUF=#64,
		OUTBUF=#65;


	! USEFUL MACROS FOR DOING I/O
	MACRO
		SKIP(OP) = IFSKIP(OP) THEN TRUE ELSE FALSE$,
		MAKEOP(OP,REG,ADDR) = (OP)<0,0>^27 + (REG)<0,0>^23 + (ADDR)<0,0>$,
		EXECUTE(X) = (REGISTER INST; INST _ X; SKIP(XCT(0,INST)))$;

	MACHOP	XCT = #256;			! THIS INSTRUCTION DOES ALL THE WORK
REQUIRE COMMON.BLI;
REQUIRE ENTRY.BLI;
COMMENT(GETFIL);

! SUBROUTINE GETFIL
! ========== ======

! THIS ROUTINE TAKES A FILE SPEC AND OPENS THE DEVICE,
! DOES A LOOKUP/INBUF OR ENTER/OUTBUF AS APPROPRIATE,
! AND RETURNS THE CHANNEL ASSIGNED. THE SPECIAL CASING OF OLDCHNL
! IS TO ALLOW THE REUSE OF THE DEVICE-CHANNEL SETUP
! AND THE BUFFERS FOR SORT SCRATCH FILES.

! LAST MODIFIED ON 14 AUG  74 BY JG.

GLOBAL ROUTINE GETFILE(TYPE,IOMODE,DEV,FILE,EXT,PPN,OLDCHN) =
BEGIN
	LOCAL	CHANNEL,CODE[5],FILEPTR;
	LABEL	GETCHN;
	MAP	FILBLK FILEPTR;

	CHANNEL _ -1;					! SO WE KNOW IF WE LOSE OUT
	IF .OLDCHN GEQ 0
	THEN CHANNEL _ .OLDCHN				! USE SPECIFIED CHANNEL
	ELSE GETCHN: INCR I FROM 0 TO 15		! OR SEARCH FOR A FREE ONE
	DO BEGIN
		IF .CHANLS[.I] EQL NULL			! DOES NOT POINT TO EXISTING FILE BLOCK
		THEN BEGIN
			CHANNEL _ .I;			! USE IT
			LEAVE GETCHN
		END
	END;
	IF .CHANNEL EQL -1
	THEN BEGIN					! WE LOST
		ERTEXT(17);				! NO CHANNELS AVAILIBLE
		RETURN -1
	END;

	IF .OLDCHN GEQ 0
	THEN BEGIN
		FILEPTR _ .CHANLS[.CHANNEL];		! USING OLD FILE BLOCK
		FILEPTR[BYTCNT] _ 0			! FORCE A UUO CALL DURING INBYT OR OTBYT CALL
	END
	ELSE BEGIN
		IF (FILEPTR _ ALLOC(FILEBLKSIZ)) EQL NULL		
			THEN RETURN -1;			! COULDN'T GET FILE BLOCK
		CHANLS[.CHANNEL] _ .FILEPTR;		! REMEMBER CHANNEL ASSIGNMENT
		FILEPTR[STATUS] _ .IOMODE;		! NOW COPY ALL THE GOODIES INTO THE FILE BLOCK
		FILEPTR[DEVICE] _ .DEV;
		FILEPTR[FILENAME] _ .FILE;
		FILEPTR[EXTENSION] _ .EXT<LH>;
		FILEPTR[PPNUM] _ .PPN;
		FILEPTR[OTBUFPTR] _ FILEPTR[BUFHDR];
		FILEPTR[INBUFPTR] _ FILEPTR[BUFHDR];
	END;
	
	% WE START OFF BY DOING AN OPEN UUO IF THIS IS A NEW CHANNEL %

	IF (IF .OLDCHN GEQ 0 THEN TRUE ELSE EXECUTE(MAKEOP(OPEN,.CHANNEL,FILEPTR[STATUS])))
	THEN IF .TYPE EQL INFILE
		THEN IF EXECUTE(MAKEOP(LOOKUP,.CHANNEL,FILEPTR[FILENAME])) ! DO LOOKUP FOR INPUT FILES
			THEN BEGIN
				IF .OLDCHN LSS 0	! GET BUFFERS FOR NEW CHANNELS
				THEN IF GETBUF(.CHANNEL,5) IS FALSE
				THEN BEGIN		! ERROR DURING BUFFER SETUP
					CHANLS[.CHANNEL] _ NULL;
					EXECUTE(MAKEOP(RELEASE,.CHANNEL,0));! BE NEAT ABOUT THINGS
					RETURN -1
				END
			END
			ELSE BEGIN			! LOOKUP FAILED
				CNVCHR(.FILEPTR[LOKENTERR],CODE,8);! GET REASON WHY
				ERTEXT(18);TTYOTS(.CODE[LANGTH],CODE[STRING]);
				PRTSPC(.CHANNEL);
				CHANLS[.CHANNEL] _ NULL;
				EXECUTE(MAKEOP(RELEASE,.CHANNEL,0));! BE NEAT
				RETURN -1
			END
		ELSE IF EXECUTE(MAKEOP(ENTER,.CHANNEL,FILEPTR[FILENAME])) ! DO ENTER FOR OUTPUT FILES
			THEN BEGIN
				IF .OLDCHN LSS 0	! GET BUFFERS FOR NEW CHANNELS
				THEN IF GETBUF(.CHANNEL,5) IS FALSE
				THEN BEGIN		! ERROR DURING BUFFER SETUP
					CHANLS[.CHANNEL] _ NULL;
					EXECUTE(MAKEOP(RELEASE,.CHANNEL,0));! BE NEAT
					RETURN -1
				END;
				OTBYT(.CHANNEL,-1,0)	! DUMMY OUT UUO TO INITIALIZE BUFFER RING
			END
			ELSE BEGIN			! ENTER LOST
				CNVCHR(.FILEPTR[LOKENTERR],CODE,8);! GET REASON WHY
				ERTEXT(19); TTYOTS(.CODE[LANGTH],CODE[STRING]);
				PRTSPC(.CHANNEL);
				CHANLS[.CHANNEL] _ NULL;
				EXECUTE(MAKEOP(RELEASE,.CHANNEL,0));! BE NEAT
				RETURN -1
			END
	ELSE BEGIN					! BIG PROBLEMS - THE OPEN FAILED !
		TTYOSX(.DEV); ERTEXT(20);
		IF .TYPE EQL INFILE
			THEN TTYOTN(0,PLIT ASCIZ 'INPUT.')
			ELSE TTYOTN(0,PLIT ASCIZ 'OUTPUT.');
		CHANLS[.CHANNEL] _ NULL;
		RETURN -1
	END;
	RETURN .CHANNEL					! IF WE GET HERE, WE HAVE A CHARMED LIFE
END;
COMMENT(INBYT);

! SUBROUTINE INBYT
! ========== =====

! THIS ROUTINE READS DATA FROM AN INPUT FILE
! USING THE SPECIFIED CHANNEL. IF COUNT IS ZERO,
! ONE BYTE (7 OR 36 BIT, DEPENDING ON THE DATA MODE)
! IS PLACED IN THE LOCATION POINTED TO BY DATAPTR.
! IF COUNT IS GREATER THAN ZERO, COUNT BYTES
! ARE READ IN AND PLACED STARTING AT DATAPTR; IN
! THIS CASE, DATAPTR SHOULD BE AN INCREMENT TYPE
! BYTE POINTER.
! LAST MODIFIED ON 1 AUG 74 BY JG.

GLOBAL ROUTINE INBYT(CHANNEL,COUNT,DATAPTR) =
BEGIN
	LOCAL FILEPTR,CODE;
	MAP   FILBLK FILEPTR;

	FUNCTION NEWBUF = IF EXECUTE(MAKEOP(IN,.CHANNEL,0)) ! GETS NEW BUFFER, MUST BE FUNCTION
			   THEN IF EXECUTE(MAKEOP(STATZ,.CHANNEL,740000))
				THEN 0			! EOF
				ELSE -1			! ERROR
			   ELSE 1;			! OK

	FILEPTR _ .CHANLS[.CHANNEL];			! GET FILEBLK POINTER
	IF .FILEPTR[BYTCNT] EQL 0			! NEED A NEW BIFFER?
	THEN IF (CODE _ NEWBUF()) NEQ TRUE
		THEN RETURN .CODE;			! EOF OR ERROR
	IF .COUNT EQL 0
	THEN BEGIN					! ONLY ONE "BYTE", DATAPTR POINTS RIGHT AT IT
		COPYIN(FILEPTR[BYTPTR],DATAPTR);
		FILEPTR[BYTCNT] _ .FILEPTR[BYTCNT]-1;	! DECREMENT REMAINING CHAR CNT
		RETURN TRUE				! ALL OK
	END
	ELSE DECR I FROM .COUNT-1 TO 0			! READ NUMBER OF "BYTES", DATAPTR IS INCREMENT TYPE
	DO BEGIN
		IF .FILEPTR[BYTCNT] EQL 0		! NEED NEW BUFFER?
		THEN IF (CODE _ NEWBUF()) NEQ TRUE
			THEN RETURN .CODE;		! EOF OR ERROR
		COPYII(FILEPTR[BYTPTR],DATAPTR);
		FILEPTR[BYTCNT] _ .FILEPTR[BYTCNT]-1;	! DECREMENT REMAINING CHAR CNT
	END;
	TRUE						! ALL OK
END;
COMMENT(OTBYT);

! SUBROUTINE OTBYT
! ========== =====

! THIS ROUTINE IS ESSENTIALLY THE SAME AS INBYT,
! EXECPT THAT IT DOES OUTPUT.
! LAST MODIFIED ON 1 AUG 74 BY JG.

GLOBAL ROUTINE OTBYT (CHANNEL,COUNT,DATAPTR) =
BEGIN
	LOCAL CODE,FILEPTR;
	MAP   FILBLK FILEPTR;

	FUNCTION NEWBUF = IF EXECUTE(MAKEOP(OUT,.CHANNEL,0)) ! GETS NEW BUFFERS, MUST BE FUNCTION
			 THEN -1			! ERROR
			 ELSE 1;			! OK

	FILEPTR _ .CHANLS[.CHANNEL];			! GET POINTER TO FILE BLOCK
	IF .FILEPTR[BYTCNT] EQL 0			! NEED NEW BUFFER?
	THEN IF (CODE _ NEWBUF()) NEQ TRUE
		THEN RETURN .CODE;			! ERROR
	IF .COUNT EQL 0					! ONE "BYTE"
	THEN BEGIN
		COPYNI(DATAPTR,FILEPTR[BYTPTR]);
		FILEPTR[BYTCNT] _ .FILEPTR[BYTCNT]-1;	! DECREMENT SPACE LEFT
		RETURN TRUE
	END
	ELSE DECR I FROM .COUNT-1 TO 0			! MUTIPLE "BYTES"
	DO BEGIN
		IF .FILEPTR[BYTCNT] EQL 0		! NEED NEW BUFFER?
		THEN IF (CODE _ NEWBUF()) NEQ TRUE
			THEN RETURN .CODE;		! ERROR
		COPYII(DATAPTR,FILEPTR[BYTPTR]);
		FILEPTR[BYTCNT] _ .FILEPTR[BYTCNT]-1	! DECREMENT SPACE LEFT
	END;
	TRUE
END;
COMMENT(CLOFIL);

! SUBROUTINE CLOFIL
! ========== ======

! THIS ROUTINE CLOSES THE FILE ON THE SPECIFIED
! CHANNEL AND RELEASES THE DEVICE IF SAVEFLAG IS FALSE.
! LAST MODIFIED ON 28 AUG 74 BY JG.

GLOBAL ROUTINE CLOFIL (CHANNEL,KILLFLAG) =
BEGIN
	EXECUTE(MAKEOP(CLOSE,.CHANNEL,0));		! CLOSE UUO
	IF EXECUTE(MAKEOP(STATZ,.CHANNEL,#740000))	! ERROR?
	THEN BEGIN					! NO
		IF  .KILLFLAG				! DO RELEASE?
		THEN BEGIN				! YES
			EXECUTE(MAKEOP(RELEASE,.CHANNEL,0));! RELEASE CHANNEL
			CHANLS[.CHANNEL] _ NULL		! FORGET CHANNEL ASSIGNMENT
		END;
		RETURN TRUE
	END
	ELSE BEGIN					! ERROR
		ERTEXT(23);
		PRTSPC(.CHANNEL);
		RETURN FALSE
	END
END;
COMMENT(RESET);

! SUBROUTINE RESET
! ========== =====

! THIS ROUTINE RESETS THE UNIVERSE (THAT IS,
! EVERYTHING BUT BLISS GLOBALS) VIA THE
! SUPER WONDERFUL RESET UUO.
! LAST MODIFIED ON 29 JUL 74 BY JG.

GLOBAL ROUTINE RESET =
BEGIN
	MACHOP CALLI=#47;
	CALLI(0,0);			! THAT'S IT, RIGHT THERE!!
	ZERO(CHANLS,16)			! ALL CHANNEL ASSIGNMENTS CEASE TO EXIST
END;
COMMENT(BUFSIZ);

! SUBROUTINE BUFSIZ
! ========== ======

! THIS ROUTINE RETURNS THE BUFFER SIZE AND DEFAULT
! NUMBER OF BUFFERS FOR THE GIVEN CHANNEL.
! LAST MODIFIED ON 14 AUG 74 BY JG.

GLOBAL ROUTINE BUFSIZ (CHANNEL) =
BEGIN
	REGISTER AC;
	MACHOP CALLI = #47;

	AC _ (.CHANLS[.CHANNEL])<ADDR>;			! GET CHANNEL
	IFSKIP CALLI(AC,#101)				! DO DEVSIZ UUO
	THEN IF .AC GTR 0
		THEN RETURN .AC;			! RETURN TASTY TIDBIT OF INFO
	FALSE						! BAD THINGS HAPPENED
END;
COMMENT(GETBUF);

! SUBROUTINE GETBUF
! ========== ======

! THIS ROUTINE ALLOCATES THE SPECIFIED NUMBER OF
! BUFFERS FOR A CHANNEL.
! LAST MODIFIED ON 14 AUG 74 BY JG.

GLOBAL ROUTINE GETBUF(CHANNEL,BUFNO) =
BEGIN
	LOCAL	FILEPTR,BUFFERSIZE,THISBUF,TEMP;
	MAP	FILBLK FILEPTR;

	IF .BUFNO LSS 1 THEN BUFNO _ 1;			! CAN'T HAVE LESS THAN ONE
	IF (BUFFERSIZE _ BUFSIZ(.CHANNEL)) IS FALSE	! GET BUFFER SIZE
	THEN BEGIN
		ERTEXT(40);
		RETURN FALSE
	END;
	IF (THISBUF _ ALLOC(.BUFFERSIZE<RH>)) IS NULL	! ALLOCATE FIRST BUFFER
		THEN RETURN FALSE;
	FILEPTR _ .CHANLS[.CHANNEL];			! GET FILE BLOCK PTR
	FILEPTR[BUFHDR]<LH> _ #400000;			! INITIALIZE RING HEADER
	FILEPTR[BUFHDR]<RH> _ .THISBUF+1;
	DECR I FROM .BUFNO-2 TO 0			! ADD REMAINING BUFFERS TO THE RING
	DO BEGIN
		IF (TEMP _ ALLOC(.BUFFERSIZE<RH>)) IS NULL ! GET BUFFER
			THEN RETURN FALSE;
		(.THISBUF+1)<RH> _ .TEMP+1;		! CHAIN FOWARD
		(.THISBUF+1)<LH> _ .BUFFERSIZE<RH>-2;	! SIZE-1
		THISBUF _ .TEMP				! CONTINUE
	END;
	(.THISBUF+1)<RH> _ .FILEPTR[BUFHDR]<RH>;	! LAST ONE ON CHAIN MUST
	(.THISBUF+1)<LH> _ .BUFFERSIZE<RH>-2;		! BE TAKEN CARE OF
	TRUE
END;

END ELUDOM;  ! END OF FILE I/O MODULE ...