Trailing-Edge
-
PDP-10 Archives
-
BB-JF18A-BM
-
sources/rms/rmsasc.b36
There are 6 other files named rmsasc.b36 in the archive. Click here to see a list.
%TITLE 'A S C I I -- ASCII record routines'
!<BLF/REQUIRE 'RMSBLF.REQ'>
MODULE ascii (IDENT = '2.0'
) =
BEGIN
!
! COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984, 1986.
! ALL RIGHTS RESERVED.
!
! 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 THAT IS NOT SUPPLIED BY DIGITAL.
!
!++
! FACILITY: RMS
!
! ABSTRACT:
!
! ASCII contains all routines dealing with I/O to ASCII or LSA
! files; this includes Line Sequence Number handling routines.
!
! ENVIRONMENT: User Mode, Interrupts deferred until return
!
! AUTHOR: Ron Lusk , CREATION DATE: 8-Mar-83
!
! MODIFIED BY:
!
! Ron Lusk, 23-Feb-84 : VERSION 2.0
! 01 - Rewrite PUTLSN and GETLSN for extended addressing.
! 02 - Return RFA to user
! 03 - Implement RB$WAA and RB$WBA
! 441 - Remove MOVST instruction and replace with ILDB/IDPB loop.
! The MOVST has an alarming tendency to insert <NUL>s in the
! middle of records when records with leading <NUL>s cross
! page boundaries. Also, CTRL-Z detection is needed for TTY:
! 445 - In edit 441, check MOVEFLAG before checking if enough
! buffer space is left; otherwise, after an RTB error,
! we neatly past the end of file to "complete" a partial $GET.
! 457 - In edit 441, we are checking to see if the remaining space
! in the user buffer - 1 is LEQ 0. It should be LSS 0.
!--
!
! TABLE OF CONTENTS
!
!
! PUTASCII -- Process $PUT macro for ASCII/LSA file
! PUTELS -- Write End-of-Line sequence to file
! PUTLSN -- Write LSN to LSA file
! GETASCII -- Process $PUT macro for ASCII/LSA file
! GETLSN -- Read LSN from LSA file
!
!
! INCLUDE FILES:
!
REQUIRE 'rmsreq';
!
! MACROS:
!
! None.
!
! EQUATED SYMBOLS:
!
GLOBAL BIND
asciv = 2^24 + 0^18 + 441; ! Edit number
!
! Symbols used for Line-sequenced files
!
LITERAL
pagemarkcode = -1, ! Line-number for page mark
pagemarksize = 2*5, ! # of chars in page-mark
pmrecsize = 2, ! Size of data in page mark
linenumflag = 1^0, ! Flag to denote line-number
lsnbufsize = %O'200', ! Size of a TOPS-10 buffer!A56
pagemark1 = ! 5 spaces, LSB set
%EXACTSTRING (5, %O'40') + linenumflag,
pagemark2 = %CHAR ($chcrt, $chffd); ! <CR><FF><NUL><NUL><NUL>
!
! OWN STORAGE:
!
! NONE
!
! EXTERNAL REFERENCES:
!
! None
!
%SBTTL 'PUTASCII -- $PUT for STM and LSA'
GLOBAL ROUTINE putascii : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes the $PUT macro for ASCII and Line-Sequenced
! ASCII files. It is placed in this module in order to
! localize all access to non-RMS file organizations.
!
! FORMAL PARAMETERS
!
! NONE.
!
! IMPLICIT INPUTS
!
! ?
!
! ROUTINE VALUE:
!
! NONE.
!
! SIDE EFFECTS:
!
! ?
!
!--
BEGIN
LOCAL
filepointer, ! Byte pointer to file buffer
userpointer : VECTOR [2], ! Byte pointer to user buffer
! (2 words to support
! non-zero sections)
destsize, ! Size of destination buffer
bytesize, ! Bytesize of file !a577
bytesperpage, ! # of bytes fit on page !a577
recordsize, ! Size of current record
bytestomove, ! Count of bytes to be
! moved to user buffer
asciibytesleft; ! Free bytes in file buffer
TRACE ('PUTASCII');
!
! If this is a TTY or LPT device, then we must reset all buffer
! counters and pointers, etc. If not, we
! must make sure that we are at the EOF.
!
IF tty OR llpt ![3] Make LPT work
THEN
BEGIN ! To reset buffer
rst [rstbytecount] = 0; ! Clear buffer
rst [rstpagptr] = CH$PTR (.curentbufferadr); ! Clear buffer
END
ELSE
BEGIN ! To check for EOF
IF rfaadr ! If RFA access !a573v
THEN ! Fetch File Page Into User Window
BEGIN
rst [Rst$g_Data_Rfa] = .rab [Rab$g_Rfa] ;
FindAsc( false );
rst[rst$v_eof]=0; ! Clear end of file
END
ELSE !a575^
IF endoffile
THEN
!+
! Update the RFA put it in the RAB
! Since we must be at EOF, the EOF byte # becomes our RFA
!-
rab [rabrfa, 0] = rst [rstdatarfa] = .rst [rsthybyte] ! update RFA
ELSE
usererror (er$nef) ! Must be at EOF
END;
!+
! Update the RFA put it in the RAB
! Since we must be at EOF, the EOF byte # becomes our RFA
!-
rab [rabrfa, 0] = rst [rstdatarfa] = .rst [rsthybyte]; ![2] update RFA
!
! If RB$WAA, advance (or whatever ELS contains) first
!
IF (.rab [rabrop, 0] AND rb$waa) NEQ 0 ![3]
THEN
putels ();
!
! For sequenced files, we must first create a line number.
!
IF sequenced
THEN
BEGIN
putlsn (); ! Write LSN into file
IF .rab [rablsn, 1] EQL pagemarkcode ! NOTE: Extend the sign
THEN
RETURN ! Ignore record if pagemark
! is output
END;
!+
! Set up file and user buffer pointers
!-
userpointer = .Rab[Rab$a_Rbf]; ! User's Ptr to buffer !a575
bytesize = .Fst[Fst$h_Bsz]; !a575
bytesperpage = ( %BPVAL / .bytesize ) * pagesize; !a575
TGUPointer( userpointer, .bytesize ); ! Make 2-word global if needed !m575
recordsize = .rab [Rab$h_Rsz]; ! Get # bytes to write
recordsize = .rab [rabrsz, 0]; ! Get # bytes to write
!+
! This is the main loop. It continues until the
! entire user record has been written to the file.
!-
WHILE .recordsize GTR 0 DO
BEGIN
!+
! Is our buffer full?
!-
IF .rst [rstbytecount] EQL pagesize*asciibytperword !
THEN
writebuffer (); ! Output full buffer
filepointer = .rst [rstpagptr]; ! Fetch file pointer
bytestomove = .recordsize; ! Assume that record
! can fit in file
asciibytesleft = ! Assume ASCII file
pagesize*asciibytperword - .rst [rstbytecount];
!+
! Use the record size or the buffer space left, whichever
! is smaller.
!-
IF .recordsize GTR .asciibytesleft !
THEN
bytestomove = .asciibytesleft; !
destsize = .bytestomove; ! Assume same size
!+
! Debugging
!-
lookat (' FILEPTR: ', filepointer);
lookat (' # BYTES: ', bytestomove);
lookat (' ASCII BYTES: ', asciibytesleft);
!+
! Do a Move-String With Left Justification to file
!-
BEGIN
LOCAL
usrbp : VECTOR [2], ! Temporary 2-word user ptr
filbp : VECTOR [2], ! Temporary 2-word file ptr
src_len, ! Temporary source length
dst_len; ! Temporary dest. length
!
! Set up for MOVSLJ instruction
!
usrbp [0] = .userpointer [0]; ! Possible 2-word byte pointer
usrbp [1] = .userpointer [1];
filbp [0] = .filepointer; ! Local BP
src_len = .bytestomove;
dst_len = .destsize;
IF moveleft_ea ( ! Move the record
usrbp, ! Source
filbp, ! Destination
src_len, ! Size of source
dst_len) EQL false ! Size of destination
THEN
rmsbug (msgmovestring); ! Move-String failed
!
! Update our file and buffer pointers
!
filepointer = .filbp; ! Update pointers
userpointer [0] = .usrbp [0];
userpointer [1] = .usrbp [1];
recordsize = .recordsize - .bytestomove;
rst [rstpagptr] = .filepointer; ! Update pointer
END; ! End MOVSLJ block
!
! Update # of bytes left in buffer
!
rst [rstbytecount] = .rst [rstbytecount] + .bytestomove;
END; ! Of WHILE loop
!
! If RB$WBA, advance (or whatever ELS contains) now
!
IF (.rab [rabrop, 0] AND rb$wba) NEQ 0 ![3]
THEN
putels ();
!+
! We have now moved the entire record from the user's buffer
! into the internal RMS-20 file buffer. We must also reset
! RSTHYBYTE to reflect the highest byte in the file.
!-
IF seqadr !m575
THEN
rst [rst$g_highest_byte] = .rst [rst$g_highest_byte] + .rab [Rab$h_Rsz]
ELSE
rst [rst$g_highest_byte] = MAX( .rst [rst$g_highest_byte],
.rab[rab$g_rfa] + .rab [Rab$h_Rsz] ) ;
!+
! If we are writing this record to a terminal, then we
! should output it immediately.
!-
IF tty OR llpt
THEN
BEGIN
writebuffer (); ! Make LPT work
Rst[Rst$h_Byte_Count] = 0; ! Clear byte count
rst [rstpagptr] = CH$PTR (.curentbufferadr); ! Reset pointer
END; !a577
RETURN
END; ! End of PUTASCII
%SBTTL 'PUTELS -- write end-of-line sequence'
GLOBAL ROUTINE putels : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Output the End-of-line sequence as requested
!
! FORMAL PARAMETERS
!
! NONE.
!
! IMPLICIT INPUTS
!
! RAB [ELS]
! RST
!
! ROUTINE VALUE:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE
!
!--
BEGIN
LOCAL
filepointer, ! Byte pointer to file buffer
userpointer : VECTOR [2], ! Byte pointer to user buffer
! (2 words to support
! non-zero sections)
c; ! Current character
TRACE ('PUTELS');
!+
! Set up file and user buffer pointers
!-
IF .rab [rabels, 0] NEQ 0 ! Did user specify end-of-line sequence?
THEN ! Yes. use it
BEGIN
IF .rmssec EQL 0
THEN
userpointer [0] = CH$PTR (.rab [rabels, 0]) ! Get user address
ELSE
BEGIN ! Extended addressing
LOCAL
temp; ! Build pointer here
temp<lh> = %O'440700' + %O'40'; ! 2-word ASCII byte pointer
temp<rh> = 0;
userpointer [0] = .temp;
temp = .rab [rabels, 0];
IF .temp<lh> EQL 0 THEN userpointer [1] = .temp OR .blksec ELSE userpointer [1] = .temp;
END
END
ELSE
userpointer = CH$PTR (UPLIT (%CHAR (13, 10, 0))); ! Use CRLF default
!+
! This is the main loop. It continues until the
! ELS has been written to the file.
!-
WHILE (c = CH$RCHAR_A (userpointer)) NEQ 0 DO ! Copy until we get a NULL
BEGIN
! Is our buffer full?
IF .rst [rstbytecount] EQL pagesize*asciibytperword THEN writebuffer (); ! Output full buffer
CH$WCHAR_A (.c, rst [rstpagptr]); ! Write the byte out
rst [rstbytecount] = .rst [rstbytecount] + 1; ! # of bytes in buffer
rst [rsthybyte] = .rst [rsthybyte] + 1; ! # of bytes in file
END; ! Of WHILE loop
RETURN
END; ! End of PUTELS
%SBTTL 'PUTLSN -- write LSN to file'
GLOBAL ROUTINE putlsn : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
! This routine takes the sequence number from the user's RAB
! and inserts it into the file as 5 ASCII digits (with bit 0
! turned on) followed by a horizontal TAB character. Note
! That the first digit is forced to be on a word boundary.
! Any bytes between the VFE of the last record and the LSN
! will be nulls.
!
! FORMAL PARAMETERS
!
! NONE.
!
! IMPLICIT INPUTS
!
! NONE.
!
! ROUTINE VALUE:
!
! NONE.
!
! SIDE EFFECTS:
!
! ?
!
! Format of a LSA record
! ====== == = === ======
!
! <Five-digit-ASCII-number><Bit-0><TAB><The-data-record><VFE>
!
!
! Format of a Pagemark
! ====== == = ========
!
! <Five-ASCII-blanks><Bit-0><CR><FF><Three-nulls>
!
!--
BEGIN
LOCAL
users_lsn, ! User's Line-Sequence-Number
buffer_lsn : REF VECTOR [2]; ! Address on page for LSN
TRACE ('PUTLSN');
!
! Fetch the line number, extending the sign.
!
users_lsn = .rab [rablsn, 1]; ! Note sign extension
!+
! Check the range of the LSN
!-
IF .users_lsn LSS pagemarkcode OR ! Less than -1?
.users_lsn GTR maxlsn ! Greater than 99999?
THEN
usererror (er$lsn); ! Don't allow such things
!+
! Check now to see if we have enough room
! left on this page to put a whole LSN and
! its <TAB>, or a whole pagemark.
!
! This means that there will, on occasion,
! be a null word near the end of the page.
! This is just fine for SOS and EDIT,
! and RMS will accept it as well.
!-
BEGIN ! Checking end of page
LOCAL
bytes_remaining; ! Free bytes in page
IF (bytes_remaining = !
(pagesize*asciibytperword) - .rst [rstbytecount]) LSS 10
THEN
BEGIN
!
! Increment the number of bytes written to file.
!
rst [rstbytecount] = .rst [rstbytecount] + .bytes_remaining;
rst [rsthybyte] = .rst [rsthybyte] + .bytes_remaining;
!
! Write this buffer to file, getting a new one.
!
writebuffer (); ! Output page
END;
END;
!+
! Calculate the number of bytes we have to
! advance the pointer in order to put it on
! a word boundary; then, increment all the counters
! and the pointer to allow for that.
!-
BEGIN
LOCAL
bump_count; ! Bytes to bump the
! counters and pointers by.
!+
! The following expression is complex, but neatly yields
! the distance from here to the next word boundary.
!-
bump_count = !
(asciibytperword - ! Difference to next word
(.rst [rstbytecount] MOD asciibytperword)) ! boundary, but turn
MOD asciibytperword; ! 5 chars into 0.
!
! Adjust the pointer and counters
!
rst [rstbytecount] = ! Bytes on page
.rst [rstbytecount] + .bump_count;
rst [rsthybyte] = ! Bytes written to file
.rst [rsthybyte] + .bump_count;
rst [rstpagptr] = ! Byte pointer
CH$PLUS (.rst [rstpagptr], .bump_count);
END;
!+
! Convert the byte pointer into an address on the page.
!-
BEGIN
!
! To determine the address of the string referenced by
! a word-aligned pointer, increment it by 1. This
! will eliminate any possibility of ambiguity in the
! address field.
!
buffer_lsn = CH$PLUS (.rst [rstpagptr], 1); ! Get whole pointer
buffer_lsn = .buffer_lsn<0, %BPADDR, 0>; ! Isolate address field
END;
!+
! Handle pagemarks and real LSNs appropriately.
!-
IF .users_lsn EQL pagemarkcode ! LSN = -1?
THEN
!+
! Put out a pagemark
!-
BEGIN
buffer_lsn [0] = pagemark1; ! First half
buffer_lsn [1] = pagemark2; ! Second half
rst [rstbytecount] = ! Update bytes on page
.rst [rstbytecount] + pagemarksize;
rst [rsthybyte] = ! Update bytes to file
.rst [rsthybyte] + pagemarksize;
rst [rstpagptr] = ! Update byte pointer
CH$PLUS (.rst [rstpagptr], pagemarksize);
END
ELSE
!+
! Write out the Line Sequence Number
!-
BEGIN
LOCAL
number_length,
double_ptr : VECTOR [2] INITIAL (0, 0),
double_lsn : VECTOR [2] INITIAL (0, 0),
ascii_lsn; ! "Buffer" for text LSN
!+
! Convert the user's LSN to ASCII. If the
! conversion fails (and it shouldn't by
! now), let the user know.
!-
double_lsn [1] = .users_lsn;
double_ptr [0] = CH$PTR (ascii_lsn);
number_length = asciibytperword OR 1^35; ! For filling
IF NOT cvtbdo ( ! Convert binary to decimal
number = double_lsn, ! LSN to convert to text
string = double_ptr, ! Destination pointer
length = number_length, fill = %C'0') ! Fill with zeroes
THEN
usererror (er$lsn); ! Something went wrong
buffer_lsn [0] = .ascii_lsn OR linenumflag; ! LSN to output buffer
!
! Set byte pointer and write the <TAB>
!
rst [rstpagptr] = ! Postion byte pointer
CH$PLUS (.rst [rstpagptr], 5);
CH$WCHAR_A (%O'11', rst [rstpagptr]); ! Write the <TAB>
!
! Update the remaining counters
!
rst [rstbytecount] = ! Update bytes on page
.rst [rstbytecount] + 6;
rst [rsthybyte] = ! Update bytes to file
.rst [rsthybyte] + 6;
END;
END; ! End of PUTLSN
%SBTTL 'GETASCII -- $GET for STM, LSA files'
GLOBAL ROUTINE getascii (moveflag) =
!++
! FUNCTIONAL DESCRIPTION:
! This routine processes the $GET macro for files with STM
! and LSA record format. For ASCII files, it transfers one
! record into the user's buffer, where a record is defined as
! being a stream of ASCII bytes terminated by a Vertical
! Format Effector.
!
! For sequenced files, full words will be transferred until
! the next line-number is found.
!
! FORMAL PARAMETERS
!
! MOVEFLAG -- Flag for record transfer:
! True: move the record ($GET)
! False: skip the record (last $GET was partial)
!
! IMPLICIT INPUTS
!
! ?
!
! ROUTINE VALUE:
!
! Number of bytes in record, or number moved if PARTIALFLAG has been set.
!
! SIDE EFFECTS:
!
! This routine sets RSTRHSIZE, which is the record header size.
! For ASCII stream files the size is zero (no record header).
! For LSA stream files the size is 6 if record begins with an LSN,
! or 10 if the record is a pagemark. This field is used by the
! $TRUNCATE processor to know how much to subtract from
! RSTDATARFA to find the beginning of the current physical record.
!
! Note: A logical record is defined as the data the user sees;
! a physical record is defined as the record header plus the
! user's data.
!
!--
BEGIN
LOCAL
significant_char_seen, ! Saw a non-<NUL> char !A441
tty_eof, ! EOF on TTY: (^Z seen) !A441
userpointer : VECTOR [2], ! Pointer to user's buffer
exitflag, ! Flag for leaving the loop
recordsize, ! Current length of record
nextword, ! Next file word for LSA files
movestatus, ! Temporary variable
buffersize, ! Size of user's buffer
bytesize; ! Byte size to use !a574
TRACE ('GETASCII');
bytesize = .Fab[Fab$v_Bsz]; !a574
!+
! If unit record device, reset buffer
! Otherwise, check for end of file
!-
IF tty OR llpt ![3] Make LPT work
THEN
BEGIN ! To reset buffer
rst [rstbytecount] = 0; ! Clear buffer
rst [rstpagptr] = CH$PTR (.curentbufferadr, ! Clear buffer
,
.bytesize ); ! File byte size !m574
END
ELSE
BEGIN
IF endoffile THEN usererror (er$eof);
END;
!+
! Set up user buffer pointer, etc.
!-
userpointer = .Rab[Rab$a_Rbf]; !a574
TGUPointer( userpointer, .bytesize ); !a574
buffersize = ! Remember size of his buffer
.rab [Rab$h_Usz] * ( %BPVAL / .Fab[Fab$v_Bsz] ); ! in bytes
recordsize = 0; ! Clear total size
rab [Rab$h_Rsz] = 0; ! Clear his record size
tty_eof = 0; ! Clear TTY: EOF flag !A441
exitflag = false; ! Loop forever
!d574
significant_char_seen = 0; ! Skip leading <NUL>s !A441
tty_eof = 0; ! Clear TTY: EOF flag !A441
exitflag = false; ! Loop forever
!+
! If we are skipping a record, then don't use a user pointer
!-
IF .moveflag EQL false THEN userpointer = 0; ! No data will be moved
!+
! Process LSN if reading an LSA stream file.
! LSA stream files have 7 bit bytes,
! no matter what the FDB says.
!-
IF sequenced AND (partialflag EQL 0)
THEN
BEGIN ! Get an LSN
getlsn (); ! Fetch the line-number
IF .rab [rablsn, 1] EQL pagemarkcode
THEN
BEGIN ! Handle pagemark
rst [rstrhsize] = stmrhpm; ! Set record header size
setflag (rst [rstflags], flgupdptr); ! Must update pointer
rst [rstrsz] = asciibytperword; ! Record size=5
IF .buffersize NEQ 0
THEN
BEGIN ! Move the pagemark record
CH$WCHAR_A (charcr, userpointer);
CH$WCHAR_A (charff, userpointer);
END;
RETURN pmrecsize ! So, recordsize is zero
END
ELSE
rst [rstrhsize] = stmrhlsn ! Set record header size
END;
IF NOT (sequenced) !
THEN
rst [rstrhsize] = stmrhasc; ! Set record header size
! for ascii stream file
!+
! This is the main loop. it continues until a VFE is
! Seen or the user's buffer is filled.
!-
UNTIL .exitflag DO
BEGIN
!+
! If buffer is empty, then re-fill it.
!-
IF .rst [rstbytecount] EQL 0 THEN readbuffer ();
IF endoffile THEN usererror (er$eof); ! Check for EOF
!+
! We will now move the entire record
! until we come to either the end
! of the file, or the end of the
! user's buffer, or a VFE. We will save
! the status of this move because we
! have to do some common clean-up before
! we need to check it.
!-
BEGIN
!++
! Beginning of edit 441 rewrite
!--
REGISTER ! !A441
user_ptr_index; ! Index to byte pointer !A441
user_ptr_index = userpointer; ! Set index register !A441
!+ !A441
! This loop copies as much of the record as
! is in this file buffer. If we encounter a
! VFE, set MOVESTATUS to FALSE and exit the
! loop. Otherwise, exit when we have
! emptied the file buffer or filled
! the user buffer.
!
! If we are reading from the TTY:, regard ^Z
! as a terminator like a VFE.
!
!-
movestatus = true; ! Set no-VFE status !A441
WHILE .rst [rstbytecount] GTR 0 DO ! While bytes in buffer !A441
BEGIN
REGISTER
char;
char = CH$RCHAR_A (rst [rstpagptr]);
rst [rstbytecount] = .rst [rstbytecount] - 1;
SELECTONE .char OF
SET
[$chnul] :
BEGIN
IF .significant_char_seen ! Seen non-<NUL> already?
THEN
BEGIN
IF .moveflag AND ! Quit if moving data !M445
(buffersize = .buffersize - 1) LSS 0 ! Space !M457
THEN
EXITLOOP; ! No - leave
idpb (char, 0, user_ptr_index); ! Yes - put byte
recordsize = .recordsize + 1; ! Bump size
END;
END;
[$chlfd, $chvtb, $chffd] :
BEGIN
IF .moveflag AND ! Quit if moving data !M445
(buffersize = .buffersize - 1) LSS 0 ! Space !M457
THEN !
EXITLOOP; ! No - leave
idpb (char, 0, user_ptr_index); ! Yes - put byte
recordsize = .recordsize + 1; ! Bump rec size
movestatus = false; ! Terminate
EXITLOOP; ! Quit looping
END;
[$chcnz] :
BEGIN
significant_char_seen = 1;
IF .moveflag AND ! Quit if moving data !M445
(buffersize = .buffersize - 1) LSS 0 ! Space !M457
THEN !
EXITLOOP; ! No - leave
idpb (char, 0, user_ptr_index); ! Yes - put byte
recordsize = .recordsize + 1; ! Bump rec size
IF tty ! EOF for TTY:?
THEN
BEGIN
tty_eof = true; ! Yes -
movestatus = false; ! Terminate
EXITLOOP; ! Quit looping
END;
END;
[OTHERWISE] :
BEGIN
significant_char_seen = 1;
IF .moveflag AND ! Quit if moving data !M445
(buffersize = .buffersize - 1) LSS 0 ! Space !M457
THEN !
EXITLOOP; ! No - leave
idpb (char, 0, user_ptr_index); ! Yes - put byte
recordsize = .recordsize + 1; ! Bump rec size
END;
TES;
END;
!++
! End of edit 441 rewrite
!--
END; ! End record reading loop
IF .movestatus EQL false THEN exitflag = true; ! Exit from loop
!++
!
! At this point, we have done the following:
!
! 1) moved a full record, or
! 2) filled the user's buffer, or
! 3) exhausted the current file buffer.
!
!--
!+
! Set up the record size field and check for
! a record which is too big for the user's buffer.
!-
IF .moveflag
THEN
BEGIN
rab [rabrsz, 0] = .recordsize; ! Update user's record size
!+
! If we are still trying to process the
! record, but the buffer is full then
! we have filled the user's buffer.
!-
IF (.exitflag EQL false) AND (.buffersize LEQ 0)
THEN
BEGIN
usrsts = er$rtb; ! Set partial record
usrstv = .recordsize; ! Return partial record size
setflag (rst [rstflags], flgpartial); ! Remember this
exitflag = true ! Leave
END
END;
END;
!+
! Store the size of this record in the user's RAB
!-
rst [rstrsz] = .recordsize; ! Pass the record size back
!
! Set the RST flag bit which tells FINDASC that
! the file pointer (PAGPTR) must be updated before
! the next operation can be done.
!
setflag (rst [rstflags], flgupdptr);
! !A441
! Check that we didn't receive EOF from TTY: !A441
! !A441
IF .tty_eof THEN usererror (er$eof); !A441
!
! We have now done everything and we can exit.
!
RETURN .recordsize
END; ! End of GETASCII
%SBTTL 'GETLSN -- read an LSN'
GLOBAL ROUTINE getlsn : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
! This routine parses a Line Sequence Number. The file is
! assumed to have been positioned to a word boundary by
! the FINDASC routine. The TAB following the line number
! will be stripped off by this routine (see note). See the PUTLSN
! routine for the format of an LSA record. Also note that
! this routine handles pagemarks (see the PUTLSN routine
! for the format of a pagemark).
!
! Note: If the character following the line number is not a
! <TAB>, it is part of the record and is not stripped.
!
! FORMAL PARAMETERS
!
! NONE.
!
! IMPLICIT INPUTS
!
! ?
!
! ROUTINE VALUE:
!
! NONE.
!
! SIDE EFFECTS:
!
! ?
!
!--
BEGIN
LOCAL
buffer_lsn : REF VECTOR [2]; ! LSN in input buffer
TRACE ('GETLSN');
!+
! If there are fewer than five bytes remaining in
! the buffer, then the buffer is empty as far
! as we are concerned.
!-
IF .rst [rstbytecount] LSS asciibytperword
THEN
BEGIN
!
! Get a new buffer and check for EOF.
!
readbuffer (); ! Get a buffer
IF endoffile THEN usererror (er$eof); ! EOF wins an error
END;
!+
! Calculate the number of bytes to the next
! word boundary, and adjust the pointer
! and counters appropriately.
!-
BEGIN
LOCAL
aligned_pointer, ! Build pointer here
bytes_to_bump; ! Bytes to next word
aligned_pointer = .rst [rstpagptr]; ! Copy the buffer pointer
buffer_lsn = .aligned_pointer<0, %BPADDR>; ! Fetch the address field
!+
! Certain word-aligned pointers (for instance, the
! default pointer to an address generated by the POINT
! pseudo-op in MACRO) have an address field which
! references the beginning of a string, and byte
! address fields describing a field to the left of
! that string (so an ILDB will get the first byte of
! the string, for instance). If this is the case,
! then the address field points to the correct
! address. Other word-aligned pointers contain the
! address of the word preceding the word really
! pointed to. This ambiguity has to be checked here.
!-
IF .aligned_pointer<30, 6> EQL %O'44' OR ! Local pointer
.aligned_pointer<30, 6> EQL %O'61' ! One-word global
THEN
buffer_lsn = .aligned_pointer<0, %BPADDR>
ELSE
buffer_lsn = .aligned_pointer<0, %BPADDR> + 1;
aligned_pointer = CH$PTR (.buffer_lsn); ! Set up word-aligned pointer
!
! Fix the counters
!
bytes_to_bump = CH$DIFF (.rst [rstpagptr], .aligned_pointer);
rst [rstpagptr] = .aligned_pointer;
rst [rstbytecount] = .rst [rstbytecount] - .bytes_to_bump;
END;
!+
! EDIT and SOS both write a word of nulls at the end
! of a block of 200 (octal) words rather than split
! the Line Sequence Number and its <TAB> between
! blocks. RMS does the same on page boundaries. If
! we find a word of nulls, it better be on a block
! boundary; we'll bump things normally if so, give an
! error if not.
!-
IF .buffer_lsn [0] EQL 0 ! Word of nulls?
THEN
BEGIN
!+
! We have three courses of action conditioned
! on the position of the null word.
!-
SELECTONE 1 OF
SET
[(.buffer_lsn MOD %O'1000') EQL %O'777'] :
!
! The null is on a page boundary,
! so read in another buffer.
!
BEGIN
!
! Set up the RFA
!
rst [rstdatarfa] = .rst [rstdatarfa] + asciibytperword;
readbuffer (); ! Get a buffer
IF endoffile THEN usererror (er$eof);
!
! The buffer address is in the current
! bucket descriptor in the RST. Fetch it
! to point at the LSN, rather than finding
! what the page pointer is really pointing
! to.
!
buffer_lsn = .cbd [bkdbktadr]; ! Address of new buffer
END;
[(.buffer_lsn MOD %O'200') EQL %O'177'] :
!
! We are on a block boundary that is not a
! page boundary (or we would have gotten
! caught in the previous select-action.
! Bump the pointers to the next block.
!
BEGIN
!
! Set up the RFA
!
rst [rstdatarfa] = .rst [rstdatarfa] + asciibytperword;
!
! Decrement the number of
! bytes left in this buffer.
!
rst [rstbytecount] = .rst [rstbytecount] - asciibytperword;
!
! Bump byte pointer.
!
rst [rstpagptr] = CH$PLUS (.rst [rstpagptr], asciibytperword);
!
! Adjust pointer to the LSN
!
buffer_lsn = .buffer_lsn + 1;
END;
[OTHERWISE] :
BEGIN
fileproblem (er$lsn); ! File consistency bug
usrerr (); ! Take error return
END;
TES;
END; ! End handling null words
!+
! Handle pagemarks and real LSNs differently.
!-
IF .buffer_lsn [0] EQL pagemark1 ! Pagemark in file?
THEN
BEGIN ! Pagemark handling
!+
! Check to see if we span pages.
!-
IF .rst [rstbytecount] EQL asciibytperword ! End of buffer?
THEN
BEGIN ! Pagemark across pages
readbuffer (); ! Get a new buffer
IF endoffile THEN usererror (er$eof);
!
! Adjust pointers to skip
! second word of pagemark.
!
rst [rstbytecount] = .rst [rstbytecount] - asciibytperword;
rst [rstpagptr] = CH$PLUS (.rst [rstpagptr], asciibytperword);
END
ELSE
BEGIN ! Normal pagemark
!
! Adjust pointers to skip
! over pagemark.
!
rst [rstbytecount] = .rst [rstbytecount] - pagemarksize;
rst [rstpagptr] = CH$PLUS (.rst [rstpagptr], pagemarksize);
END;
!
! Update byte position in file
!
rst [rstdatarfa] = .rst [rstdatarfa] + pagemarksize;
!
! Return -1 for a pagemark
!
rab [rablsn, 1] = pagemarkcode; ! Return -1 as LSN
END ! Pagemark handling
ELSE
BEGIN ! LSN handling
!+
! Convert the linenumber to binary.
!-
BEGIN ! LSN conversion
LOCAL
number_length,
double_number : VECTOR [2] INITIAL (0, 0),
double_pointer : VECTOR [2] INITIAL (0, 0);
number_length = asciibytperword;
double_pointer [0] = .rst [rstpagptr];
IF NOT cvtdbo ( ! Convert the number
number = double_number, !
length = number_length, !
string = double_pointer) !
THEN
BEGIN
fileproblem (er$lsn); ! Something wrong with file
usrerr (); ! Tell user
END
ELSE
rab [rablsn, 1] = .double_number [1]; ! LSW of result
END; ! LSN conversion
!
! Presumably, all has gone OK so far, so
! bump the bytepointer and decrement the
! number of bytes remaining on the page.
!
rst [rstpagptr] = CH$PLUS (.rst [rstpagptr], asciibytperword);
rst [rstbytecount] = .rst [rstbytecount] - asciibytperword;
rst [rstdatarfa] = .rst [rstdatarfa] + asciibytperword;
!+
! If the LSN was (by chance) on the end of a page,
! we have to read a new buffer.
!-
IF .rst [rstbytecount] EQL 0 ! End of page?
THEN
BEGIN
readbuffer (); ! Get a new buffer
IF endoffile THEN usererror (er$eof);
END;
!+
! Look for a <TAB>. If there is no <TAB>,
! then the first character is really part
! of a record. If there is a <TAB>, strip
! it off the record.
!-
IF CH$RCHAR (.rst [rstpagptr]) EQL $chtab ! Is it a <TAB>?
THEN
BEGIN
!
! Skip over <TAB>
!
rst [rstpagptr] = CH$PLUS (.rst [rstpagptr], 1);
!
! Account for the <TAB>
!
rst [rstbytecount] = .rst [rstbytecount] - 1;
rst [rstdatarfa] = .rst [rstdatarfa] + 1;
END;
END; ! LSN handling
! [2] RFA will be returned to user before this has fiddled with it
! because FINDASC will have set it.
END; ! End of GETLSN
END ! End of Module ASCII
ELUDOM