Google
 

Trailing-Edge - PDP-10 Archives - BB-J939B-BM - binary/ezio10.b36
There are 6 other files named ezio10.b36 in the archive. Click here to see a list.
!<BLF/LOWERCASE_USER>
MODULE ezio10 (OTS = '',
		LANGUAGE (BLISS36),
		IDENT = '1(4)'
%IF %VARIANT
%THEN
		    ,
		    BLISS10_REGS
%FI
		) =
BEGIN


! Functional description:
!    Provides basic file and tty i/o services to bliss-36
!    Programs.
!
!			  COPYRIGHT (c) 1977, 1978 BY
!	      DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
!
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
! ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE AND WITH THE
! INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR  ANY  OTHER
! COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
! OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
! TRANSFERRED.
!
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE  WITHOUT  NOTICE
! AND  SHOULD  NOT  BE  CONSTRUED  AS  A COMMITMENT BY DIGITAL EQUIPMENT
! CORPORATION.
!
! DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF  ITS
! SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
!

!++
! FACILITY: A transportable, Easy to use, I/O interface (EZIO)
!
! ABSTRACT:
!    Provides basic file and TTY I/O services to BLISS-36 programs.
!
! ENVIRONMENT: TOPS-10 user program subroutine.
!
! AUTHOR: Paul Dickson & Bruce Dawson, CREATION DATE: sometime in 1977
!
! MODIFIED BY:
!
!	Bruce Dawson, 24-July-78 : VERSION 0(1)
! 01	- FILIN was returning -1 when it got EOF in the process of getting
!	another buffer. However, there may still be data in the buffer, so
!	the returning of -1 was delayed until the next request for a buffer.
!
! 02	FILOPN was only checking the low order bit to determine input or 
!	output. The documentation says only 1 or 0 is allowed. The check
!	was made more strigent.
!
! 03	FILIN apparently never worked after the functionality to ignore
!	line numbers was added. It should work now.
!
!   Bruce Dawson, 4-Oct-78 : version 1(4)
! 04	Edit 03 didn't quite do it all. One expression in FILIN was
!	undeleted. Also, EOF was initialized for a channel in FILOPN.
!
!
!--
!
!   TABLE OF CONTENTS
!
FORWARD ROUTINE
    filcls,					! Closes a file.
    filin,					! Gets one line from a file.
    filopn,					! Opens a file.
    filout,					! Writes a string to a file.
    getoct,					! Picks up an octal word.
    getsix;					! Picks up a sixbit word.

FIELD
    words =
	SET
	w0 = [0, 0, 36, 0],
	w1 = [1, 0, 36, 0],
	w2 = [2, 0, 36, 0],
	w3 = [3, 0, 36, 0]
	TES,
    bufh =
	SET
	bufptr = [1, 0, 36, 0],			! Byte pointer into buffer.
	bufcnt = [2, 0, 36, 0],			! Count of bytes.
	eof = [3, 0, 1, 0]		! EOF indicator bit		!A001
	TES,
    opnf =
	SET
	statbits = [0, 0, 36, 0],		! Status bits.
	device = [1, 0, 36, 0],			! Device name.
	obufh = [2, 18, 18, 0],			! Output buffer header.
	ibufh = [2, 0, 18, 0]			! Input buffer header.
	TES,
    lookf =
	SET
	filename = [0, 0, 36, 0],		! File name.
	ext = [1, 18, 18, 0],			! Extension.
	proj = [3, 18, 18, 0],			! Project number.
	prog = [3, 0, 18, 0]			! Programmer number.
	TES;

LITERAL
    NUMCHANS = 3,				! Number of channels open at once
						! (-1 excluded)
    failure = 0,				! Return codes.
    success = 1,
    gotdev = 1,					! Codes for parser action.
    gotfil = 2,
    gotext = 3,
    gotp = 4,
    gotpn = 5,
    goterr = 0;


STRUCTURE
    matrix [r, c; nr, nc] =
	[nr*nc]
	(matrix + r*nc + c)<0, 36>;

!<BLF/NOFORMAT>
BIND
    action = UPLIT(		! Parser action table.
	gotdev,	gotfil,	gotfil,	0,	0,	gotfil,	!
	0,	gotfil,	gotfil,	0,	0,	gotfil,	!
	0,	0,	gotext,	0,	0,	gotext,	!
	0,	0,	0,	gotp,	0,	0,	!
	0,	0,	0,	0,	gotpn,	0) : matrix[5,6];
!<BLF/FORMAT>

OWN
    carr_return : INITIAL(%O'15'),		!
    linefeed : INITIAL(%O'12'),			!
!    io : BLOCKVECTOR [NUMCHANS, 3]		! Buffer headers go here. !D001
!	FIELD (words, bufh) INITIAL( REP NUMCHANS*3 OF (0)),		  !D001
    io : BLOCKVECTOR [NUMCHANS, 4]	! Buffer headers go here.	  !A001
	FIELD (words, bufh) INITIAL( REP NUMCHANS*4 OF (0)),		  !A001
    

    unseen,					! Unscanned length of filespec.
    first : INITIAL(1),				! First-time flag.
    spec;					! Pointer to filespec.

LITERAL
    openuuo = %O'50',				! Monitor calls.
    renameuuo = %O'55',
    lookupuuo = %O'76',
    enteruuo = %O'77',
    releaseuuo = %O'71',
    ttcall = %O'51',
    calli = %O'47',
    inuuo = %O'56',
    outuuo = %O'57',
    outchr = %O'1',				! TTCALL codes.
    inchwl = %O'4',
    reset = %O'0';				! CALLI codes.

MACRO
    bldop (op, ac, y) =
	BEGIN
	LOCAL inst_;
	inst_ = 0;
	inst_<27,9> = op;
	inst_<23,4> = ac;
	inst_<0,18> = y;
	machop(%O'256',0,inst_)
	END%,
    bldskip (op, ac, y) =
	BEGIN
	LOCAL inst_;
	inst_ = 0;
	inst_<27,9> = op;
	inst_<23,4> = ac;
	inst_<0,18> = y;
	machskip(%O'256',0,inst_)
	END%;

MACRO
    put_char (arg) =
	BEGIN
	CH$WCHAR_A (arg, io [.chan, bufptr]);
	IF (io [.chan, bufcnt] = .io [.chan, bufcnt] -1) LEQ 0
	THEN
	    IF bldskip (outuuo, .chan, 0)
	    THEN RETURN failure
	END	%;

BUILTIN
    machop,
    machskip;
GLOBAL ROUTINE filcls (chan) =
!+
! Functional description:
!    Closes a file previously opened by filopn.
!
! Inputs:
!    Chan:	a channel number.
!-
    BEGIN

    IF .chan LSS 0
    THEN
	RETURN;

    IO[.CHAN,EOF] = 0;
    bldop (releaseuuo, .chan, 0);
    RETURN success
    END;
GLOBAL ROUTINE filin (chan, len, stgptr) =
!+
! Functional description:
!    Inputs one line from the specified channel.
!
! Inputs:
!    Chan:	channel number. -1 is tty.
!    Len:	length of string for buffer.
!    Stgptr:	string pointer.
!
! Value:
!    Count of characters read.  -1 means eof was hit.
!
! Discussion:
!    Characters are read until a linefeed is hit, or
!    The string is filled, whichever comes first.  if
!    The string is too short, the next call will pick
!    Up where the previous one left off.
!    Line numbers (and the tab following) are skipped over.
!-
    BEGIN

    LOCAL
	ptr,					! Pointer to buffer.
	ch,					! A character.
	count;				! Count of chars read.

    ptr = .stgptr;				! Initialize.
    count = 0;

    IF .chan LSS 0				! Tty?
    THEN
	BEGIN

	INCR k FROM 1 TO .len DO
	    BEGIN
	    machop (ttcall, inchwl, ch);
	    CH$WCHAR_A (.ch, ptr);
	    count = .count + 1;

	    IF .ch EQL .linefeed
	    THEN
		BEGIN
		ch = CH$RCHAR (CH$PLUS (.ptr, -2));

		IF .ch GEQ %O'13' AND 		!
		    .ch LEQ %O'15'
		THEN
		    RETURN .count - 2		! Trime cr/ff/vt,lf
		ELSE
		    RETURN .count - 1;		! Trim lf only.

		END;

	    END;

	IF .ch GEQ %O'13' AND .ch LEQ %O'15'
	THEN
	    RETURN .len - 1
	ELSE
	    RETURN .len

	END;

    WHILE .count LSS .len DO
	BEGIN

	! Read in a new buffer if necessary
	IF .io [.chan, bufcnt] leq 0
	THEN

!	    IF bldskip (inuuo, .chan, 0)			    !D001
!	    THEN						    !D001
!		RETURN -1					    !D001
!	    ELSE						    !D001
!		io [.chan, bufcnt] = .io [.chan, bufcnt] - 1;	    !D001
!								    !D001
	    BEGIN						    !A001
	    LOCAL						    !A003
		buf : ref vector;	! Pointer to buffer	    !A003

	    ! Return if EOF set by prior input			    !A001
	    IF .io[.chan, eof] THEN RETURN -1;			    !A001

	    ! If the INUUO skips, then the last block in the file was read
	    io [.chan, bufptr] = %O'4400000000';		    !A003
	    IF bldskip (inuuo, .chan, 0)			    !A001
	    THEN io[.chan, eof] = 1;				    !A001

	    ! Change all sequence numbers in the buffer to nulls.   !A003
	    ! Note that at this point (after the INUUO), the buffer !A003
	    ! count and pointer are in terms of words.		    !A003
	    buf = .io [.chan, bufptr] + 1;			    !A003
	    INCR i from 0 to .io [.chan, bufcnt] - 1 do		    !A003
		IF .buf[.i]					    !A003
		THEN						    !A003
		    BEGIN	! If line # bit on, then clear word !A003
		    buf[.i] = 0;				    !A003
		    ch$wchar (0, ch$ptr(buf[.i+1]));	! Clear tab !A003
		    END;					    !A003

	    ! Make the count and pointer in the buffer header be    !A003
	    !  for characters instead of words.			    !A003
	    io[.chan, bufptr] = ch$ptr(.io[.chan, bufptr] + 1);	    !A003
	    io[.chan, bufcnt] = .io[.chan, bufcnt] * 5;		    !A003
	    END;						    !A001

	ch = CH$RCHAR_A (io [.chan, bufptr]);  ! Read a character.
	io [.chan, bufcnt] = .io [.chan, bufcnt] - 1;

	IF .ch NEQ 0			! Skip nulls.
	THEN
	    BEGIN
	    CH$WCHAR_A (.ch, ptr);      ! Put character in caller's buffer.
	    count = .count + 1;
	    END;

	IF .ch EQL .linefeed
	THEN
	    BEGIN
	    ch = CH$RCHAR (CH$PLUS (.ptr, -2));

	    IF .ch GEQ %O'13' AND
		.ch LEQ %O'15'
	    THEN
		RETURN .count - 2		! Trim cr/ff/vt,lf
	    ELSE
		RETURN .count - 1;		! Trim lf only.

	    END;

	! Return count if LF is not the last thing in the buffer. If
	! no characters are in the buffer (don't forget about NULs), then
	! return EOF.
	IF .IO[.CHAN,EOF] AND .COUNT EQL 0 THEN RETURN -1;	    !A004
	IF .IO[.CHAN,EOF] THEN RETURN .COUNT;			    !D003!A004

	END;

    ! If we managed to fill up the caller's buffer, then we must
    ! check the last character in the buffer. This character must
    ! be effectively deleted if it is a carriage control character.

    IF .ch GEQ %O'13' AND .ch LEQ %O'15'
    THEN
	RETURN .len - 1
    ELSE
	RETURN .len

    END;
GLOBAL ROUTINE filopn (chan, speclen, specptr, output) =
!+
! Functional description:
!    Opens a file.
!
! Inputs:
!    Chan:	a channel number from 0 to 15.
!    Speclen:	length of the filespec.
!    Specptr:	string pointer to a filespec of the form:
!		  Device:filnam.ext[p,pn]
!		With the usual defaults.
!    Output:	low-order bit is 1 for output. bits <1,4> are mode.
!
! Value:
!    1 If successful. otherwise 0.
!-
    BEGIN

    LOCAL
	state,					! State of the parser.
	sep,					! Code of seperator.
	w,					! A word with a lexeme in it.
	lookarg : 				! Lookup/enter arg block
	    BLOCK [4] FIELD (words, lookf),
	opnarg : 				! Open arg block.
	    BLOCK [3] FIELD (words, opnf);

    IF .CHAN GTR NUMCHANS-1
    THEN RETURN FAILURE;

    IF .first					! Initialize everything once.
    THEN
	BEGIN
	first = 0;
	machop (calli, 0, reset)
	END;

    IF .chan LSS 0				! TTY?
    THEN
	RETURN success;

    state = 0;					! Initialize.
    spec = .specptr;
    unseen = .speclen;
    opnarg [device] = %sixbit'DSK   ';		! Move in defaults.
    opnarg [statbits] = 0;
    opnarg [obufh] = opnarg [ibufh] = 0;
    io [.chan, w0] = io [.chan, w1] = io [.chan, w2] = 0;
    io [.chan, eof] = 0;
    lookarg [w0] = lookarg [w1] = lookarg [w2] = lookarg [w3] = 0;

    WHILE .state LSS 5 DO
	BEGIN
	sep = (IF .state LSS 3 THEN getsix ELSE getoct) (w);

	CASE .action [.state, .sep] FROM 0 TO 5 OF
	    SET

	    [gotdev] :
		opnarg [device] = .w;

	    [gotfil] :
		lookarg [filename] = .w;

	    [gotext] :
		lookarg [ext] = .w<18, 18>;

	    [gotp] :
		lookarg [proj] = .w;

	    [gotpn] :
		lookarg [prog] = .w;

	    [goterr] :
		RETURN failure
	    TES;

	state = (IF .sep LSS 5 THEN .sep + 1 ELSE .sep)
	END;

    IF .output EQL 1				! Set up buffers.	!R002
    THEN
	opnarg [obufh] = io [.chan, w0]
    ELSE
	opnarg [ibufh] = io [.chan, w0];


    IF NOT bldskip (openuuo, .chan, opnarg)
    THEN
	RETURN failure;

    w = (IF .output EQL 1 THEN enteruuo ELSE lookupuuo);		!R002

    IF NOT bldskip (.w, .chan, lookarg)
    THEN
	BEGIN
	bldop (releaseuuo, .chan, 0);
	RETURN failure
	END;

    IF .output EQL 1							!R002
    THEN

	IF bldskip (outuuo, .chan, 0)
	THEN
	    RETURN failure;

    RETURN success
    END;
GLOBAL ROUTINE filout (chan, len, stgptr) =
!+
! Functional description:
!    Outputs a string on the specified channel.
!
! Inputs:
!    Chan:	Channel number. -1 is TTY.
!    Len:	Length of string. If negative, current
!		buffer is output.
!    Stgptr:	String pointer.
!
! Value:
!    1 If everything goes Ok. Otherwise 0.
!-
    BEGIN

    LOCAL
	ch,					! A character.
	ptr;					! Pointer to next char to send.

    ptr = .stgptr;				! Initialize.

    IF .chan LSS 0				! TTY?
    THEN
	BEGIN

	INCR k FROM 1 TO .len DO
	    BEGIN
	    ch = CH$RCHAR_A (ptr);
	    bldop (ttcall, outchr, ch)
	    END;

	bldop (ttcall, outchr, carr_return);
	bldop (ttcall, outchr, linefeed);
	RETURN success
	END;

    IF .len LSS 0				! Force block?
    THEN
	RETURN NOT bldskip (outuuo, .chan, 0);

    INCR k FROM 1 TO .len DO
	BEGIN
	put_char (CH$RCHAR_A (ptr));
	END;

    put_char (.carr_return);
    put_char (.linefeed);
    RETURN success
    END;
ROUTINE getoct (wadr) =
!+
! Functional description:
!    Scans an octal word from the filespec.
!
! Inputs:
!    Wadr:	address of where the word goes.
!
! Value:
!    A code indicating the reason for stopping.  this
!    Is useful to the parser.
!-
    BEGIN

    LOCAL
	len,
	ch;					! A character.

    BIND
	w = .wadr;				! The destination.

    w = len = 0;				! Initialize.

    WHILE .unseen GTR 0 DO
	BEGIN
	ch = CH$RCHAR_A (spec);			! Get a character.

	IF .ch GEQ %C'0' AND .ch LEQ %C'7'	! Test numeric.
	THEN
	    w = .w^3 + (.ch - %C'0')
	ELSE

	    IF .ch EQL %C','
	    THEN
		RETURN 3			! Test stopping.
	    ELSE
		RETURN 4;

	unseen = .unseen - 1
	END;

    RETURN 5
    END;
ROUTINE getsix (wadr) =
!+
! Functional description:
!    Scans a sixbit word from the filespec.
!
! Inputs:
!    Wadr:	address of where the word goes.
!
! Value:
!    A code indicating the reason for stopping.  this
!    Is useful to the parser.
!-
    BEGIN

    LOCAL
	vp,					! Pointer to output string.
	len,					! Count of characters taken.
	ch;					! A character.

    BIND
	w = .wadr;				! The destination.

    w = len = 0;				! Initialize.
    vp = CH$PTR (w, 0, 6);

    WHILE .unseen GTR 0 DO
	BEGIN
	ch = CH$RCHAR_A (spec);			! Get a character.

	IF .ch GEQ %C'a' AND .ch LEQ %C'z'
	THEN
	    ch = .ch - 32;			! Uppercase.

	SELECTONE .ch				! See if should stop.
	OF
	    SET

	    [%C':'] :
		RETURN 0;

	    [%C'.'] :
		RETURN 1;

	    [%C'['] :
		RETURN 2;

	    [OTHERWISE] :
		BEGIN

		IF .ch LEQ 32
		THEN
		    RETURN 5;

		IF .len LSS 6
		THEN
		    BEGIN
		    len = .len + 1;
		    CH$WCHAR_A (.ch + 32, vp)
		    END

		END
	    TES;

	unseen = .unseen - 1
	END;

    RETURN 5
    END;

END

ELUDOM