Trailing-Edge
-
PDP-10 Archives
-
BB-4157F-BM_1983
-
fortran/ots-debugger/forio.mac
There are 25 other files named forio.mac in the archive. Click here to see a list.
SEARCH FORPRM
TV FORIO I/O ROUTINES,7(3252)
;COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1981, 1983
;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.
COMMENT \
***** Begin Revision History *****
1100 CKS 5-Jun-79
New
1263 JLC 09-Feb-81 QAR 10-05487
Fix -10 backspace. SOJLE should be SOJGE.
1272 DAW 19-Feb-81
A few low-risk changes to support extended addressing.
1303 JLC 25-Feb-81
Folded -10 code for %irec into the -20 code for DIREC, made
it call %SAVE4 instead of %SAVE3 as it was clobbering P4.
Save line sequence number in the DDB.
1306 DAW 26-Feb-81
New arg-list format from %SAVE
1310 DAW 26-Feb-81
Full words in DDB for END=, ERR=, IOST=, AVAR= addresses.
1316 JLC 5-Mar-81
Major changes for magtape handling, switching i/o direction.
1325 JLC 9-Mar-81
Yet more changes to magtape I/O on the -10
1332 JLC 11-Mar-81
Installed dump mode I/O for the -10.
1333 JLC 11-Mar-81
Fix to backspace over eof.
1336 JLC 12-Mar-81
Fix to dump mode I/O, removed extraneous saves of pntr/count
for the -10, added one where crucial (just before FILOP in
binary I/O).
1341 JLC 13-Mar-81
Add code to handle rewind of file that hasn't been opened
yet for the -10.
1343 DAW 16-Mar-81
A few changes for extended addressing.
1346 JLC 16-Mar-81
Fixes to -10 backspace file, skip file, and rewind.
1353 JLC 18-Mar-81
More fixes for -10 magtape ops. BAKEOF was not backspacing
over the last block of the file.
1357 JLC 19-Mar-81
More fixes to magtape ops. BAKEOF was not handling null
files correctly. Installed code to prevent creation of
null file for rewind, skip file, backfile, or unload with
no OPEN.
1360 EDS 19-Mar-81 Q10-05866
Range check UNIT numbers used in I/O statements.
1361 JLC 20-Mar-81
Fix some typos in code to prevent null file creation.
1363 JLC 24-Mar-81
Minor fixes to magtape and error typout,
added missing global (%iset) called from foropn.
1365 JLC 25-Mar-81
Typo in WAIT FILOP.
1366 JLC 26-Mar-81
Still more typos, plus BAKEOF bug, plus END FILE was not
incrementing the block #.
1374 JLC 31-Mar-81
Replace code to turn off D%END for terminals. Previous code
was wiping T1, which contained valuable data.
1376 JLC 31-Mar-81
Fix -10 backspace code to eliminate cache-sweep bugs for
SMP (removed clearing of use-bits).
1377 JLC 01-Apr-81
Change load/store FLGS to move/movem FLAGS, since it was
a full word. Minor fix to -10 backspace. Minor changes
to UNFO, moved check for empty window from end of loop
to beginning of BLT code.
1401 JLC 30-Apr-81
Put back code to clear use-bits, was merely masking another
bug.
1402 JLC 06-Apr-81
Transplant input record initialization to where it belongs,
new subroutine called %IRINI. Move setting of CRLF suppression
to %IREC.
1406 JLC 06-Apr-81
Minor bug in backspace for -10, backspace beyond block 1
sometimes would not work.
1410 JLC 07-Apr-81
Move record buffer setup to %IRINI and %ORINI in preparation
for separation of record buffer. Modify and separate EXPRB
for same preparation.
1411 DAW 08-Apr-81
Use IJFN and OJFN instead of JFN.
1412 JLC 09-Apr-81
Fix minor problem reading fixed-length record files. Fix
backspace for the -20 for fixed-length record files.
1413 DAW 10-Apr-81
Get rid of flag D%MTOP. FOROTS doesn't need to check
whether or not its doing a magtape operation on every IO
statement.
1414 DAW 10-Apr-81
MTOP operations were ignoring ERR=.
1416 JLC 10-Apr-81
Separate record buffers. Install DTA rewind and unload.
1422 JLC 13-Apr-81
Typo in separate record buffers.
1423 DAW 13-Apr-81
Put %SETD in FORIO (was in FOROPN).
1424 JLC 14-Apr-81
Typo in %IRINI made DECODE non-existent.
1427 JLC 15-Apr-81
Changed RSIZ to be a word in the DDB. Make FORIO
ignore MODE=DUMP if ACCESS=RANDOM.
1430 JLC 15-Apr-81
Typo in -20 backspace broke it.
1432 JLC 16-Apr-81
Was trashing returned AC T3 in DIREC. Changed code to return
result in IRCNT(D) instead.
1433 JLC/CKS 16-Apr-81
Fix for binary backspace.
1435 CKS 16-Apr-81
More binary backspace fixes.
1436 JLC 16-Apr-81
More of edit 1432. Return result in IRCNT for DECODE also.
1443 JLC 17-Apr-81
Make EOFN(D) represent fixed number of bytes in file. EOF
detected by comparing BYTN with EOFN.
1444 JLC 21-Apr-81
Fix bug caused by edit 1443; it was smashing T1.
1445 DAW 21-Apr-81
Rework code around UNFSW to make it more understandable.
1450 JLC 22-Apr-81
Fix DECODE new record code.
1451 JLC 23-Apr-81
Special code for dump mode I/O in mtops.
1453 JLC 24-Apr-81
Make dump mode backspace and skiprecord work for magtape.
Insert if20 end after EOFN setup code.
1454 JLC 24-Apr-81 QAR 20-01364
Change EOFN if we switch from formatted to unformatted.
1455 JLC 27-Apr-81
Fix bug from edit 1452. Must not set D%LIN/D%LOUT on the way
out of magtape operations.
1460 JLC 28-Apr-81
Fix typo in edit 1453. It thought most files were dump mode.
1463 JLC 7-May-81
Many major changes. See FOROTS.MAC revhist.
1464 DAW 21-May-81
Error messages.
1465 JLC 15-May-81
Major changes to -20 I/O.
1474 JLC 22-May-81
Bug in %PTOF, thought WSIZ was in words, was in bytes.
1476 JLC 26-May-81
Bug in unformatted I/O, was looking at EOFN for non-disk files.
1501 JLC 27-May-81
More bugs, this time in random I/O, caused by changed calling
sequence for MAPW.
1502 JLC 28-May-81
Install defensive WAIT operations in magtape code.
1505 JLC 01-Jun-81
Many bug fixes in disk and magtape backspace operations.
Turn off EOF and initialize things for BACKFILE and
SKIPFILE.
1506 CKS 2-Jun-81
Add SLST77 and ELST77, temporarily equated to F-66 equivalents,
SLIST and ELIST.
1511 JLC 5-Jun-81
More edits to magtape code, for SKIPFILE and BACKFILE.
1516 JLC 10-Jun-81
Yet another bug, this time in disk backspace. WSIZ is not
in words! Fix end-of-record handling for unformatted I/O.
1532 DAW 14-Jul-81
OPEN rewrite: Base level 1
1535 JLC 14-Jul-81
EOF handling correction, both to zero arrays correctly
and to handle IOSTAT correctly.
1536 JLC 15-Jul-81
Minor edits.
1542 JLC 17-Jul-81
Fix ERR and END processing and %MVBLK.
1546 JLC 20-Jul-81
Fix DEC% to call DECINI. Fix TIREC for -20 to allocate
record buffer if none there yet.
1547 DAW 20-Jul-81
Replacement for old %CHKDR routine.
1550 JLC 20-Jul-81
Fix DECODE, it had off-by-one error. Fix X format, it referenced
stuff in DDB without D. Fix setup of record buffers - make sure
it happens in %ORINI or %IRINI.
1553 JLC 23-Jul-81
Fix ENCODE and DECODE again. Setup IRPTR properly in TIREC.
Eliminate useless routine ENCINX.
1560 DAW 28-Jul-81
OPEN rewrite: Base level 2
1567 JLC 30-Jul-81
More fixes to ENCODE/DECODE, output buffer setup, prompting.
1572 JLC 31-Jul-81
ENCODE - setup entire string with blanks for initialization.
1574 BL 3-Aug-81
Missing IF20 conditional around G.PRP
1575 JLC 05-Aug-81
Fix record zeroing again.
1577 DAW 11-Aug-81
Create "ENDNUL" routine to make the "drop a null at EOR"
hack work correctly.
1601 DAW 12-Aug-81
ENDFILE to a disk file was trying to open it for input on the -20.
1604 DAW 12-Aug-81
More of 1601-type stuff, for DIVERT.
1607 DAW 13-Aug-81
Fix bug in FIND code.
1613 JLC 19-Aug-81 Q10-6390
Use a character count, not a word count, in backspace of
ASCII files.
1614 JLC 19-Aug-81
Move setting of D%MOD into DOREC. Remove END= branching
for end-of-record for files with no crlf at end, thus
EOF becomes a valid record terminator, and the program
will get END= at the next read.
1622 JLC 21-Aug-81
Rewrite ENCODE/DECODE again, rework record positioning
subroutines for output, so that X, T format reaaly work.
1625 DAW 21-Aug-81
Get rid of "DF".
1627 DAW 24-Aug-81
On TOPS-20, UNLOAD and REWIND no longer need a filename
1630 JLC 24-Aug-81
Make illegal operations on magtape a fatal error.
1631 DAW 24-Aug-81
Set D%MOD in UNFO.
1632 JLC 24-Aug-81
Fixed OPAD to output spaces instead of random trash for X and
T format.
1633 JLC 25-Aug-81
On TOPS-20, SKIPFILE and BACKFILE no longer need a filename.
1634 JLC 25-Aug-81
ORPOS was left set at FIXREC, caused records to be too large.
1635 JLC 25-Aug-81
Fix for edit 1633, plus ENDFILE can't work that way.
1637 JLC 26-Aug-81
DECODE bug. IRCNT was not getting set up properly.
1642 JLC 27-Aug-81
Replace %FILOP calls with FILOPs.
1643 JLC 27-Aug-81
More code for faster EOL handling. Modify IRBUF/ORBUF to be full
words so ENCODE/DECODE will work with extended addressing.
1645 DAW 28-Aug-81
Column 1 before errors in DIVERT'ed file.
1646 DAW 28-Aug-81
DTA REWIND and UNLOAD used wrong channel.
1647 DAW 28-Aug-81
DTA REWIND and UNLOAD to not require an existing file.
1652 DAW 1-Sep-81
Fix DUMP mode I/O on TOPS-10; make "IOE" a "?" error.
1653 JLC 1-Sep-81
Return -1 (illegal LSN) for non-LINED files and LINED files
with no LSN.
1663 JLC 8-Sep-81
Fixed ill mem read for non-existent pages in read-only file.
Added code to record top page number, so unused pages can be
unmapped.
1665 DAW 8-Sep-81
Make a D.TTY hack to get error messages right; delete refs to U.TTY.
1676 DAW 9-Sep-81
%OCRLF to always output a CRLF, and not use "U".
1702 JLC 10-Sep-81
More fix to non-existent page stuff, unmapping unused pages.
Add code to prevent expansion of random files on -10 by
merely touching the page (not possible on -20).
1703 DAW 11-Sep-81
Fix printing of too many CRLF's in errors when a TTY file is open.
1704 JLC 11-Sep-81
Fix SETPOS not to pad a blank when we are at desired position.
Also typo in RDW for -10 in edit 1702.
1705 JLC 11-Sep-81
Fix more serious T-format bug. T1 was not working on output,
as it got stored as position 0. Now ORPOS contains desired
position of NEXT character.
1706 DAW 11-Sep-81
Lots of changes to errors.
1707 JLC 14-Sep-81
Edit 1705 broke %IBACK.
1712 JLC 15-Sep-81
Fixed more bugs in t-format, created IRPOS.
Eliminated D%ERR!
1716 JLC 16-Sep-81
Changed the names of ISPOS, OSPOS, etc., to make things less
confusing. Fixed typo due to confusion.
1722 JLC 16-Sep-81
Code for IRPOS more complicated than originally envisaged.
1730 JLC 18-Sep-81
More fixes for T-format.
1735 DAW 22-Sep-81
-20 DISK APPEND files now get EOF for READ.
1737 DAW 23-Sep-81
Fix processing of REREAD error "RBR".
1740 DAW 23-Sep-81
More REREAD code.
1745 JLC 24-Sep-81
Made IRBLN, ORBLN, and IRLEN full words. Removed all refs
to IRPOS, now unnecessary.
1761 JLC 5-Oct-81
Fixed ENDFILE on disk, did not open file for output before.
1774 DAW 8-Oct-81
Avoid "?Unexpected TAPOP. error" for typical errors.
1775 JLC 9-Oct-81
Fix ^Z handling.
1777 DAW 9-Oct-81
FILOP. CLOSE before RELEASE where appropriate.
2005 JLC 15-Oct-81
Fix unmapping of unused pages so it does it for random files.
On -10, update .RBSIZ so we don't return zeroes for data
that's there.
2006 JLC 15-Oct-81
Control-Z change broke DECODE by meddling with IRCNT, which
should be inviolate before the "device-dependent" call.
2010 JLC 19-Oct-81
Make EOFN and BYTN live for the -10.
2016 JLC 20-Oct-81
Fix SLISTs and ELISTs to differentiate between -66 and -77
programs and give 1-trip (i.e., 1 entry) for zero-trip
lists.
2033 DAW 19-Nov-81
Change symbol "LTYPE" to "%LTYPE" to avoid conflict with
user symbol.
Give error if user tries to do random I/O without an OPEN
statement with a RECORDSIZE specifier.
Pay attention to ERR= and IOSTAT= for ENCODE and DECODE.
Fix dollar format to make T and X format have some effect
at end of record.
***** Begin Version 6A *****
2042 TGS 2-FEB-82 20-17208
Change NREC(D) to NREC(U) at RNRER1, MOPEND (inside IF20 conditional),
and MOPEND (inside IF10 conditional) end-of-file routines so record
counts are correctly incremented/decremented.
Note: this was really done here by JLC during rework.
***** Begin Version 7 *****
3003 JLC 26-Oct-81
Add error msg for character I/O to unformatted file - not
supported yet.
3012 JLC 4-Nov-81
Rework FOROTS call arg copier. No more LTYPE.
Small extended addressing change in SMAP - get extended
address for page reference.
3014 JLC 5-Nov-81
Fixed more bugs in SLIST.
3035 JLC 5-Feb-82
Rework of binary I/O with characters.
3036 BL 10-Feb-82
Inserted %OMBYT, routine to put out character strings.
3037 JLC 11-Feb-82
Fixed dump mode I/O. Made all errors on magtape fatal.
3041 JLC 11-Feb-82
Fixed character/binary I/O word-alignment bit-clearing; table
was set up wrong (missing commas).
3042 JLC 12-Feb-82
Fix ordinary binary I/O, broken by char/binary patch. Was
calling UOALIN with pntr/count=0, which set 010700 lh in bp.
3043 JLC 18-Feb-82
Fix internal files. Was getting address of descriptor for
length (left out @), then stored wrong AC anyway.
3056 JLC 23-Mar-82
Catch I/O within I/O. Give warning for attempt to write
too much data in binary or image files with fixed-length
records. Fix TTY EOF for multi-line input.
3104 JLC 8-Apr-82
IALIGN had IDIV/IMUL backwards.
3105 JLC 9-Apr-82
Fix dump-mode I/O to return properly via %SETAV.
3113 JLC 22-Apr-82
Fix IWORD so it never calls ONXTW with a non-zero byte count.
3122 JLC 28-May-82
Moved place where %UDBAD was getting set up. Changed some
global refs. Moved POSEFL into FORIO.
3125 JLC 3-Jun-82
Moved AC save routine back to hiseg again.
3136 JLC 26-Jun-82
Extensive rework of record output for improved performance.
3140 JLC 2-Jul-82
Fix IMAP for -10 and -20 - EOF return was changed to non-skip.
Fix %OMBYT so it doesn't try to MOVSLJ with 0 or negative byte
counts.
3141 JLC 2-Jul-82
Code at end of %EOREC was not restoring things properly.
Fix ^Z in -20 code, was not appearing on its own line. Remove
two-direction code from IRSET, move it to TIREC.
3150 JLC 12-Jul-82
Fix input of fixed-length random records so it checks for
record not written. Moved code that checks for EOF - it would not
detect a second occurrence for fixed-length record files.
Save P1 and P2 in sequential and random window routines.
Fix -10 random write bug, was comparing something to EOFN
with CAIG.
3152 JLC 14-Jul-82
Reload P1/P2 in multiple places after calls to IMAP.
3153 JLC 20-Jul-82
Fixed -10 problem caused by new EOF handling of RANDOM files.
3157 BL 9-Aug-82
Fix backspace bug. When backspacing to beginning of binary
sequential file, if the desired record was entirely within
the previous window, UNFBSR attempted to PMAP the previous
BUFCNT pages, whether or not they were in fact real pages
within the file.
3161 JLC 16-Aug-82
Fixed some extended addressing bugs for ENCODE/DECODE by
adjusting the byte pointer separately rather than relying
on the updated one provided by MOVSLJ, which ends up
being 2-word on the KL. Installed V7 version of TSG patch
for record numbers bigger than a half-word. Coded around
microcode bug with MOVSLJ and padding with 0 byte count.
Fixed %IBYTC so it doesn't do LDB on null record. Flush
buffer for TOSTR on -10.
3165 JLC 28-Aug-82
Recode part of random I/O handling so it can process files
larger than 256K blocks long.
3166 JLC 31-Aug-82
Eliminate multiply-defined symbol CHKEOL in -10 code.
3167 JLC 31-Aug-82
Removed %SPEOL, as it accomplished nothing.
3170 AHM 1-Sep-82
Fix bug in edit 3165. Remove index field from reference to
WPAGE at RECTPG to avoid ?Illegal memory READs in section 1.
Module: FORIO
3171 JLC 1-Sep-82
Fix random I/O on the -10, wrong AC used (typo).
3172 JLC 2-Sep-82
Fix random I/O on the -10. CLRPAG was clearing the ACs
instead of the proper pages.
3173 JLC 3-Sep-82
Another fix to -10 random I/O, was not calculating when to
truncate block correctly, was not saving .RBSIZ when it
should have been.
3174 JLC 4-Sep-82
Fix TTY input on the -10, checked the wrong char for EOL,
did not do record expansion correctly.
3200 JLC 24-Sep-82
Store LSN for variable-length records. Fix -20 TTY input
of large records. Use BPW calcs rather than assuming 1200
bytes/block on the -10.
3201 JLC 4-Oct-82
Move unit range check to before I/O within I/O check.
3202 JLC 26-Oct-82
Fix many bugs, and provide basic support for ANSI (8-bit)
tapes for TOPS-20, since most of the work is done by the
monitor. Install new code to read and backspace fixed-
length, non-word-aligned records.
3203 JLC 31-Oct-82
Fix SPCWD problem.
3212 JLC 11-Nov-82
Update and consolidate -20 magtape code so that B36FLG(D) controls
whether formatted or unformatted I/O is done. Fix unformatted
I/O routines for mixed-mode files.
Fix CCOC handling logic - only change CCOC words when we
are about to do TTY output, then restore them to just
previous to the output.
3213 JLC 12-Nov-82
More consolidation, minor bug fixes - OWORD was assuming
T1 was preserved, and it wasn't.
3215 JLC 15-Nov-82
Fix magtape bugs, typos in FORIO and FOROPN.
3221 JLC 18-Nov-82
Fix magtape bugs.
3222 JLC 19-Nov-82
Fix more magtape bugs, plus binary backspace on the -10.
3223 JLC 22-Nov-82
Fix more backspace bugs, EOFN for error output.
3225 JLC 24-Nov-82
Fix yet more magtape bugs (namely, characters left at the
end of the last word needed to be cleared). Type nulls as
nulls, since they are more likely to appear more in V7.
3226 JLC 29-Nov-82
Make BZ the default for ENCODE/DECODE and internal files.
3231 JLC 14-Dec-82
Change error message for illegal length internal files
to a valid error, since they can be user-initiated. For READ,
simumulate TOPS-10 EXEC handling of <ESC> - output a CRLF,
and treat it as an EOL character.
3237 JLC 18-Dec-82
Fixed yet another bug in ENFILL.
3240 JLC 20-Dec-82
Removed ENFILL, caused too many bugs and could not work in
extended addressing.
3247 RJD 7-Jan-83
Add ERJMPs after PMAP calls used to set up the file windows
for sequential and random files.
3250 JLC 7-Jan-83
Fix TOREC, was changing CCOC words and not changing them
back if nothing in record.
3251 JLC 9-Jan-83
In edit 3250, check ORCNT, not IRCNT.
3252 JLC 12-Jan-83
Insert FORPRG macro call, to purge MONSYM-created global
symbols which don't have "%" or ".".
***** End Revision History *****
\
ENTRY IN%,OUT%,RTB%,WTB%,NLI%,NLO%,ENC%,DEC%,FIND%,MTOP%
ENTRY IOLST%,FIN%,IFI%,IFO%
INTERN %IBYTE,%OBYTE,%IBYTC,%OMBYT,%OMSPC,%IMBYT
INTERN %IRECS,%OREC,%EOREC,%ORECS,%OCRLF
INTERN %IBACK,%OSMAP,%OBUF,%SETAV,%RTMSK,%CUNIT
INTERN %RIPOS,%SIPOS,%ROPOS,%SOPOS,%CIPOS,%COPOS
IF10,< INTERN %RANWR,%BACKB,%CLRBC,%BAKEF,%ISET >
EXTERN %UDBAD,%MSPAD,%MSLJ,%NAMLN
EXTERN %POPJ,%POPJ1,%SAVE1,%SAVE2,%SAVE3,%SAVE4,%CPARG,%SAVAC,%SAVIO
EXTERN %PUSHT,%POPT,%JPOPT
EXTERN %IFSET,%OFSET,%IFORM,%OFORM,%LDI,%LDO,%NLI,%NLO,%LDIST,%LDOST
EXTERN %IOERR,%ABORT,%IONAM
EXTERN %SETIN,%SETOUT,%CHKNR,%CRLF
EXTERN %GTBLK,%MVSPC,%GTSPC
EXTERN %ISAVE,%SIZTB,%DDBTA
EXTERN %EDDB,U.RERD,U.ERR,D.TTY,U.TTY,G.PRP
IF20,< EXTERN %CLSOP,%OCCOC,%CCMSK >
IF10,< EXTERN %ST10B,%CALOF,%CLSER,%FREBLK >
EXTERN %OPENX,%LSTBF
EXTERN %UNNAM
EXTERN IO.ADR,IO.NUM,IO.SIZ,IO.INC,IO.TYP,IO.INS
EXTERN %ALCHF,%DECHF
SEGMENT CODE
SUBTTL I/O SETUP
;Formatted read -- READ (u,f)
FENTRY (IN)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,FMTCNV ;CONVERT ARG LIST
PUSHJ P,FINGO ;GO DO I/O SETUP
SKIPN T.FMT ;IS THERE A FORMAT ADDR?
JRST LDI% ;NO. IT'S LIST-DIRECTED INPUT
XMOVEI T1,%IFORM ;SETUP FOR FORMAT EXECUTION
MOVEM T1,IOSUB(D)
PJRST %IFSET ;GO ENCODE FORMAT
;Formatted write -- WRITE (u,f)
FENTRY (OUT)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,FMTCNV ;CONVERT ARG LIST
PUSHJ P,FOUTGO ;GO DO I/O SETUP
SKIPN T.FMT ;IS THERE A FORMAT ADDR?
JRST LDO% ;NO. IT'S LIST-DIRECTED OUTPUT
XMOVEI T1,%OFORM ;SETUP FOR FORMAT EXECUTION
MOVEM T1,IOSUB(D)
PJRST %OFSET ;GO ENCODE FORMAT
;Unformatted read
FENTRY (RTB)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,UNFCNV ;CONVERT ARG LIST
PUSHJ P,UINGO ;GO DO I/O SETUP
LOAD T1,MODE(D) ;GET MODE
CAIN T1,MD.DMP ;DUMP?
JRST RDUMP ;YES. GO SET IT UP
XMOVEI T1,UNFI ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST UISET ;GO DO INITIAL SETUP
RDUMP: XMOVEI T1,DMPIN ;SETUP FOR DUMP MODE INPUT
MOVEM T1,IOSUB(D)
PJRST DMPSET
;Unformatted write
FENTRY (WTB)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,UNFCNV ;CONVERT ARG LIST
PUSHJ P,UOUTGO ;GO DO I/O SETUP
LOAD T1,MODE(D) ;GET MODE
CAIN T1,MD.DMP ;DUMP?
JRST WDUMP ;YES. GO DO DUMP OUTPUT
XMOVEI T1,UNFO ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST UOSET ;GO DO INITIAL SETUP
WDUMP: XMOVEI T1,DMPOUT ;SETUP FOR DUMP MODE OUTPUT
MOVEM T1,IOSUB(D)
PJRST DMPSET
;Namelist input
FENTRY (NLI)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,NMLCNV ;CONVERT ARG LIST
PUSHJ P,FINGO ;GO DO I/O SETUP
PJRST %NLI ;AND DO I/O
;Namelist output
FENTRY (NLO)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,NMLCNV ;CONVERT ARG LIST
PUSHJ P,FOUTGO ;GO DO I/O SETUP
PJRST %NLO ;AND THE I/O
;DECODE
FENTRY (DEC)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,ENCCNV ;CONVERT ARG LIST
XMOVEI T1,[ASCIZ /DECODE/]
MOVEM T1,%IONAM ;Set statement name
PUSHJ P,IOARG ;Move args to A.XXX
PUSHJ P,SETDE ;SET UP DDB POINTING TO STRING
MOVX T1,DECUNI ;STORE "UNIT"
STORE T1,UNUM(U)
MOVEI T1,DI.ENC ;SET "DEVICE" TYPE TO INTERNAL FILE
STORE T1,INDX(D) ;STORE IN DDB
MOVEM U,%UDBAD ;SAVE DDB ADDRESS FOR IOLST
PUSHJ P,DECINI ;INIT BUFFER PNTR
XMOVEI T1,%IFORM ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST %IFSET ;GO ENCODE THE FORMAT
;ENCODE
FENTRY (ENC)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,ENCCNV ;CONVERT ARG LIST
XMOVEI T1,[ASCIZ /ENCODE/]
MOVEM T1,%IONAM ;Set statement name
PUSHJ P,IOARG ;Move args to A.XXX
PUSHJ P,SETDE ;SET UP DDB POINTING TO STRING
MOVX T1,ENCUNI ;STORE "UNIT"
STORE T1,UNUM(U)
MOVEI T1,DI.ENC ;SET "DEVICE" TYPE TO INTERNAL FILE
STORE T1,INDX(D) ;STORE IN DDB
MOVEM U,%UDBAD ;SAVE DDB ADDRESS FOR IOLST
PUSHJ P,ENCINI ;Init for ENCODE
XMOVEI T1,%OFORM ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST %OFSET ;GO ENCODE THE FORMAT
FENTRY (MTOP)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,MTCNV ;CONVERT ARG LIST
XMOVEI T1,[0] ;DON'T KNOW STATEMENT NAME YET
MOVEM T1,%IONAM
PUSHJ P,IOARG ;Move args to A.XXX
PUSHJ P,CHKUNT ;Check for unit number in range
;(Goes to ABORT% if unit is bad)
PJRST MTOP ;OK, Go do it and return.
FENTRY (LDI)
XMOVEI T1,%LDI ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST %LDIST ;DO LIST-DIRECTED INPUT SETUP
FENTRY (LDO)
XMOVEI T1,%LDO ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST %LDOST ;DO LIST-DIRECTED OUTPUT SETUP
;INTERNAL FILE INPUT
;INTERNAL FILES ARE NOT REALLY FILES AT ALL - THEIR "RECORDS"
;ARE THE ELEMENT(S) OF A CHARACTER EXPRESSION, VARIABLE, OR ARRAY,
;GIVEN AS THE UNIT ARGUMENT IN A READ OR WRITE STATEMENT.
;THE FOLLOWING CODE SETS UP A FAKE DDB (OR USES ONE IF IT EXISTS
;ALREADY), SETS THE "DEVICE TYPE" TO INTERNAL FILE FOR %IREC
;CALLS, SETS THE FOROTS RECORD BUFFER POINTER/COUNT TO THE
;SPECIFIED CHARACTER VARIABLE OR ARRAY, AND STARTS UP FORMATTED I/O.
FENTRY (IFI)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
XMOVEI T1,[ASCIZ /READ/]
MOVEM T1,%IONAM ;Set statement name
PUSHJ P,IOARG ;Move args to A.XXX
PUSHJ P,SETDE ;SET UP DDB POINTING TO STRING
MOVX T1,IFIUNI ;STORE "UNIT"
STORE T1,UNUM(U)
MOVEI T1,DI.INT ;SET "DEVICE" TYPE TO INTERNAL FILE
STORE T1,INDX(D) ;STORE IN DDB
MOVEM U,%UDBAD ;SAVE DDB ADDRESS FOR IOLST
PUSHJ P,IFINI ;INIT BUFFER PNTR
XMOVEI T1,%IFORM ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST %IFSET ;GO ENCODE THE FORMAT
;INTERNAL FILE OUTPUT
;SAME AS INTERNAL FILE OUTPUT, BUT SETS UP FOR OUTPUT CALLS
FENTRY (IFO)
PUSHJ P,%SAVAC ;SAVE ACS
PUSHJ P,%CPARG ;AND COPY ARGS
XMOVEI T1,[ASCIZ /WRITE/]
MOVEM T1,%IONAM ;Set statement name
PUSHJ P,IOARG ;Move args to A.XXX
PUSHJ P,SETDE ;SET UP DDB POINTING TO STRING
MOVX T1,IFOUNI ;STORE "UNIT"
STORE T1,UNUM(U)
MOVEI T1,DI.INT ;SET "DEVICE" TYPE TO INTERNAL FILE
STORE T1,INDX(D) ;STORE IN DDB
MOVEM U,%UDBAD ;SAVE DDB ADDRESS FOR IOLST
PUSHJ P,IFOINI ;INIT FOR INTERNAL FILE OUTPUT
XMOVEI T1,%OFORM ;SETUP FOR IOLST CALLS
MOVEM T1,IOSUB(D)
PJRST %OFSET ;GO ENCODE THE FORMAT
IOARG: SETZM A.UNIT ;CLEAR BLOCK SO UNSPECIFIED ARGS ARE 0
MOVE T1,[A.UNIT,,A.UNIT+1]
BLT T1,IOARGS+MAXKWD-1
HLRE T3,-1(L) ;GET NEGATIVE COUNT
ARGLP: LDB T1,[POINTR ((L),ARGKWD)] ;GET KWD OF ARGUMENT
CAILE T1,MAXKWD ;WITHIN RANGE?
$ECALL IKV,%ABORT ;NO. ILLEGAL KEYWORD VALUE
XMOVEI T2,@0(L) ;Get arg address
MOVEM T2,IOARGS(T1) ;STORE ARG IN BLOCK
LDB T2,[POINTR ((L),ARGTYP)] ;GET TYPE
MOVEM T2,IOTYPS(T1) ;STORE TYPE
ADDI L,1 ;INCR ARG PNTR
AOJL T3,ARGLP ;TRANSFER ENTIRE ARG BLOCK
SKIPE T1,A.IOS ;IOSTAT VARIABLE?
SETZM (T1) ;YES. CLEAR IT
POPJ P, ;DONE
SEGMENT DATA
;COPIED ARGS, MUST BE CONSECUTIVE, IN ORDER ON KEYWORD NUMBER (IK.XXX)
IOARGS: BLOCK 1 ;ZERO KEYWORD - SKIPPED ARG
A.UNIT: BLOCK 1 ;UNIT= [ADDRESS OF VALUE]
A.FMT:: BLOCK 1 ;FMT= [ADDRESS]
A.FMS:: BLOCK 1 ;FORMAT SIZE [ADDRESS OF VALUE]
A.END:: BLOCK 1 ;END= [ADDRESS]
A.ERR:: BLOCK 1 ;ERR= [ADDRESS]
A.IOS:: BLOCK 1 ;IOSTAT= [ADDRESS]
A.REC:: BLOCK 1 ;REC= [ADDRESS]
A.NML:: BLOCK 1 ;NAMELIST ADDRESS [ADDRESS]
A.MTOP: BLOCK 1 ;MTA OP CODE [ADDRESS OF VALUE]
A.HSA:: BLOCK 1 ;ENCODE/DECODE ARRAY ADDRESS [ADDRESS]
A.HSL:: BLOCK 1 ;ENCODE/DECODE RECORD LENGTH [ADDRESS OF VALUE]
MAXKWD==.-IOARGS ;MAX LEGAL IO ARG KWD NUMBER
;NOW FOR THE DATA TYPES
IOTYPS: BLOCK 1 ;ZERO KEYWORD - SKIPPED ARG
T.UNIT:: BLOCK 1 ;UNIT= [ADDRESS OF VALUE]
T.FMT:: BLOCK 1 ;FMT= [ADDRESS]
T.FMS:: BLOCK 1 ;FORMAT SIZE [ADDRESS OF VALUE]
T.END:: BLOCK 1 ;END= [ADDRESS]
T.ERR:: BLOCK 1 ;ERR= [ADDRESS]
T.IOS:: BLOCK 1 ;IOSTAT= [ADDRESS]
T.REC:: BLOCK 1 ;REC= [ADDRESS]
T.NML:: BLOCK 1 ;NAMELIST ADDRESS [ADDRESS]
T.MTOP:: BLOCK 1 ;MTA OP CODE [ADDRESS OF VALUE]
T.HSA:: BLOCK 1 ;ENCODE/DECODE STRING ADDRESS [ADDRESS]
T.HSL:: BLOCK 1 ;ENCODE/DECODE STRING LENGTH [ADDRESS OF VALUE]
SEGMENT CODE
FOUTGO: XMOVEI T1,[ASCIZ /WRITE/] ;Set statement name
MOVEM T1,%IONAM
PUSHJ P,IOARG ;MOVE ARGS TO A.XXX
PUSHJ P,CHKUNT ;Check unit number in range
; (Goes to ABORT% or ERR= if not).
PUSHJ P,SETD ;Setup D and U
PUSHJ P,SETASC ;SET MODE TO ASCII IF ZERO
PUSHJ P,OPNDDB ;OPEN DDB IF NECESSARY
PUSHJ P,%SETOUT ;Get file opened for output.
PUSHJ P,CHKFRM ;CHECK IF FORMATTED I/O OK
SKIPE A.REC ;RANDOM I/O?
PUSHJ P,FORMPW ;YES. MAP THE DESIRED RECORD
SKIPN ORBUF(D) ;ANY RECORD BUFFER YET?
PUSHJ P,GETORB ;NO. CREATE ONE
PJRST ORINI ;GO INIT OUTPUT RECORD
UOUTGO: XMOVEI T1,[ASCIZ /WRITE/] ;Set statement name
MOVEM T1,%IONAM
PUSHJ P,IOARG ;MOVE ARGS TO A.XXX
PUSHJ P,CHKUNT ;Check unit number in range
; (Goes to ABORT% or ERR= if not).
PUSHJ P,SETD ;Setup D and U
PUSHJ P,SETBIN ;SET MODE TO BINARY IF ZERO
PUSHJ P,OPNDDB ;OPEN DDB IF NECESSARY
PUSHJ P,%SETOUT ;Get file opened for output.
PUSHJ P,CHKUNF ;CHECK IF UNFORMATTED I/O OK
SKIPE A.REC ;RANDOM I/O?
PUSHJ P,UORMPW ;YES. MAP THE DESIRED RECORD
POPJ P,
FINGO: XMOVEI T1,[ASCIZ /READ/]
MOVEM T1,%IONAM
PUSHJ P,IOARG ;MOVE ARGS TO A.XXX
PUSHJ P,CHKUNT ;Check unit number in range
; (Goes to ABORT% or ERR= if not).
MOVE T1,%CUNIT ;GET UNIT #
CAME T1,[RRUNIT] ;REREAD?
JRST INGO1 ;No
MOVE T1,U.RERD ;GET REREAD UNIT
CAMN T1,[RRUNIT] ;IS THERE ONE?
$ECALL RBR,%ABORT ;NO. ?REREAD not preceded by READ
MOVEM T1,%CUNIT ;YES. USE IT
PUSHJ P,SETD ;SETUP D AND U
PUSHJ P,%SETIN ;Get file opened for input.
PUSHJ P,CHKFRM ;CHECK IF FORMATTED I/O IS CORRECT
PJRST REREAD ;POINT TO LAST RECORD
INGO1: PUSHJ P,SETD ;Do implicit OPEN if necessary
PUSHJ P,SETASC ;SET MODE TO ASCII IF ZERO
PUSHJ P,OPNDDB ;OPEN DDB IF NECESSARY
PUSHJ P,%SETIN ;Get file opened for input.
PUSHJ P,CHKFRM ;CHECK IF FORMATTED I/O IS CORRECT
LOAD T1,UNUM(U) ;Get unit number
HRREM T1,U.RERD ;Store REREAD unit
SKIPE A.REC ;RANDOM I/O?
PUSHJ P,FIRMPW ;YES. MAP THE DESIRED RECORD
PJRST %IREC ;READ A RECORD
UINGO: XMOVEI T1,[ASCIZ /READ/]
MOVEM T1,%IONAM
PUSHJ P,IOARG ;MOVE ARGS TO A.XXX
PUSHJ P,CHKUNT ;Check unit number in range
; (Goes to ABORT% or ERR= if not).
PUSHJ P,SETD ;SETUP DDB
PUSHJ P,SETBIN ;SET MODE TO BINARY IF ZERO
PUSHJ P,OPNDDB ;OPEN DDB IF NECESSARY
PUSHJ P,%SETIN ;Get file opened for input.
PUSHJ P,CHKUNF ;CHECK IF UNFORMATTED I/O IS CORRECT
SKIPE A.REC ;RANDOM I/O?
PUSHJ P,UIRMPW ;YES. MAP THE DESIRED RECORD
POPJ P,
;CHKxxx checks for conflicts between the current READ or WRITE
;statement and the previous OPEN statement, if any.
;For instance, doing RANDOM I/O (i.e., specifying a record number)
;for a sequential file is illegal, and an unformatted READ or WRITE
;with a file opened for FORMATTED I/O is illegal. FOROTS does not
;try to switch the mode of the file.
CHKFRM: LOAD T1,FORM(D) ;GET FORM=
CAIE T1,FM.FORM ;FORMATTED?
SETOM FUMXD(D) ;NO. SET MIXED-MODE FLAG
JRST CHKRAN ;GO CHECK RANDOM
CHKUNF: LOAD T1,FORM(D) ;GET FORM=
CAIE T1,FM.UNF ;UNFORMATTED?
SETOM FUMXD(D) ;NO. SET MIXED-MODE FLAG
CHKRAN: MOVE T1,FLAGS(D) ;GET DDB FLAGS
SKIPN A.REC ;RANDOM I/O STATEMENT?
JRST CHKNR ;NO. GO MAKE SURE IT'S NOT RANDOM FILE
TXNE T1,D%RAN ;RANDOM FILE?
POPJ P, ;YES
DMOVE T2,[EXP [ASCIZ /direct/],[ASCIZ /sequential/]]
$ECALL CDI,%ABORT ;REPORT RANDOM I/O TO SEQ FILE
CHKNR: TXNN T1,D%RAN ;RANDOM FILE?
POPJ P, ;NO
DMOVE T2,[EXP [ASCIZ /sequential/],[ASCIZ /direct/]]
$ECALL CDI,%ABORT ;REPORT SEQ I/O TO RANDOM FILE
;Routine to check UNIT= to see if unit number is in range
;Call:
; PUSHJ P,CHKUNT
; <return here if ok>
;If unit is out of range and ERR= or IOSTAT= was specified,
; the program returns to the appropriate place.
;Otherwise, the error message is typed and the program is aborted.
;Uses T1,T2
CHKUNT: HRRE T2,@A.UNIT ;GET UNIT
MOVEM T2,%CUNIT ;SAVE AS CURRENT UNIT
CAML T2,[MINUNIT] ;RANGE CHECK. BELOW NEGATIVE UNITS
CAILE T2,MAXUNIT ; OR UNIT BEYOND RANGE OF DDBTAB
$ECALL IUN,%ABORT ;ILLEGAL UNIT NUMBER
JUMPGE T2,CHKUDB ;IF POSITIVE, NAME IS CORRECT
HRRZ T3,%UNNAM(T2) ;NEGATIVE, GET THE REAL NAME
XMOVEI T3,(T3) ;GET EXTENDED ADDR
MOVEM T3,%IONAM ;SAVE IT
CHKUDB: SKIPE %UDBAD ;IS I/O IN PROGRESS?
$ECALL IWI,%ABORT ;YES. THAT'S FATAL!
POPJ P, ;Ok, return
;HERE FROM IOLST% OR FIN% WHEN I/O IS COMPLETE
%SETAV: SETZM %UDBAD ;CLEAR THE UDB PNTR
MOVE T1,CREC(D) ;GET CURRENT RECORD NUMBER
ADDI T1,1 ;POINT TO NEXT ONE
SKIPE T2,AVAR(D) ;Get address of ASSOCIATE VARIABLE
MOVEM T1,(T2) ;There is one, store next record number
SETZM %NAMLN ;TELL ERROR PROCESSOR STATEMENT DONE
POPJ P, ;DONE. RETURN TO USER PROG
;ROUTINE TO SET UP A DDB FOR ENCODE/DECODE
SETDE: SKIPE U,%EDDB ;DDB ALREADY CREATED?
JRST CLRDE ;YES. USE IT
MOVEI T1,ULEN ;Get length of unit block
PUSHJ P,%GTBLK
MOVE U,T1 ;Point U to it
MOVEM U,%EDDB ;Save for use on next ENCODE/DECODE
MOVEI T1,DLEN ;GET LENGTH OF DDB
PUSHJ P,%GTBLK ;GET AN EMPTY DDB
MOVEI D,(T1) ;POINT D TO IT
MOVEM D,DDBAD(U) ;Remember it in the unit block
MOVEI T1," " ;PAD WITH SPACES
STORE T1,PADCH(U)
MOVEI T1,IBPW ;GET BYTES/WORD
MOVEM T1,BPW(D) ;SAVE IT IN DDB
MOVE T1,[ASCII / /] ;GET A WORD OF SPACES
MOVEM T1,SPCWD(D) ;SAVE IT ALSO
MOVEI T1,(POINT 7,0,34) ;7-BIT BYTE POINTER
STORE T1,BYTPT(D) ;SAVE IT
MOVEI T1,BL.ZERO ;BZ FOR DECODE AND IFI
STORE T1,BLNK(U)
CLRDE: MOVEM U,%UDBAD ;FLAG WE'VE STARTED I/O
MOVE D,DDBAD(U) ;GET DDB ADDR
MOVX T1,D%CLR ;CLEAR ALL TEMP FLAGS
ANDCAM T1,FLAGS(D)
POPJ P,
;ROUTINES TO CONVERT POSITIONAL ARG BLOCKS TO KEYWORD ARG BLOCKS
FMTCNV: LDB T1,[POINTR ((L),ARGKWD)] ;GET KWD FIELD OF FIRST ARG
JUMPN T1,%POPJ ;NONZERO, NEW-STYLE CALL
CAMLE L,[-4,,-1] ;AT LEAST 4 ARGS?
JRST IOCNV1 ;NO, SKIP /FMT
MOVEI T1,IK.FMT ;GET KWD NUMBER FOR /FMT
DPB T1,[POINTR (3(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
CAMLE L,[-5,,-1] ;AT LEAST 5 ARGS?
JRST IOCNV1 ;NO, SKIP FORMAT SIZE
MOVEI T1,IK.FMS ;GET KWD NUMBER FOR FORMAT SIZE
DPB T1,[POINTR (4(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
IOCNV1: CAMLE L,[-6,,-1] ;AT LEAST 6 ARGS?
JRST IOCNV2 ;NO, SKIP /REC
MOVEI T1,IK.REC ;GET KWD NUMBER FOR /REC
DPB T1,[POINTR (5(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
IOCNV2: MOVEI T1,IK.UNIT ;GET KWD NUMBER FOR /UNIT
DPB T1,[POINTR ((L),ARGKWD)] ;STORE IN LOCAL ARG LIST
IOCNV3: CAMLE L,[-2,,-1] ;AT LEAST 2 ARGS?
POPJ P, ;NO, DONE
MOVEI T1,IK.END ;GET KWD NUMBER FOR /END
DPB T1,[POINTR (1(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
CAMLE L,[-3,,-1] ;AT LEAST 3 ARGS?
POPJ P, ;NO, DONE
MOVEI T1,IK.ERR ;GET KWD NUMBER FOR /ERR
DPB T1,[POINTR (2(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
POPJ P, ;DONE
UNFCNV: LDB T1,[POINTR ((L),ARGKWD)] ;GET KWD FIELD OF FIRST ARG
JUMPN T1,%POPJ ;NONZERO, NEW-STYLE CALL
JRST IOCNV1
NMLCNV: LDB T1,[POINTR ((L),ARGKWD)] ;GET KWD FIELD OF FIRST ARG
JUMPN T1,%POPJ ;NONZERO, NEW-STYLE CALL
CAMLE L,[-4,,-1] ;AT LEAST 4 ARGS?
JRST IOCNV2 ;NO, NO NAMELIST ADDRESS
MOVEI T1,IK.NML ;GET KWD NUMBER FOR NAMELIST
DPB T1,[POINTR (3(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
JRST IOCNV2 ;GO DO STANDARD ARGS
ENCCNV: LDB T1,[POINTR ((L),ARGKWD)] ;GET KWD FIELD OF FIRST ARG
JUMPN T1,%POPJ ;NONZERO, NEW-STYLE CALL
MOVEI T1,IK.HSL ;GET KWD NUMBER FOR STRING LENGTH
DPB T1,[POINTR ((L),ARGKWD)] ;STORE IN LOCAL ARG LIST
CAMLE L,[-4,,-1] ;AT LEAST 4 ARGS?
JRST IOCNV3 ;NO, SKIP /FMT
MOVEI T1,IK.FMT ;GET KWD NUMBER FOR /FMT
DPB T1,[POINTR (3(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
CAMLE L,[-5,,-1] ;AT LEAST 5 ARGS?
JRST IOCNV3 ;NO, SKIP FORMAT SIZE
MOVEI T1,IK.FMS ;GET KWD NUMBER FOR FORMAT SIZE
DPB T1,[POINTR (4(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
CAMLE L,[-6,,-1] ;AT LEAST 6 ARGS?
JRST IOCNV3 ;NO, SKIP STRING ADDRESS
MOVEI T1,IK.HSA ;GET KWD NUMBER FOR STRING ADDRESS
DPB T1,[POINTR (5(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
JRST IOCNV3 ;GO DO STANDARD ARGS
MTCNV: LDB T1,[POINTR ((L),ARGKWD)] ;GET KWD FIELD OF FIRST ARG
JUMPN T1,%POPJ ;NONZERO, NEW-STYLE CALL
CAMLE L,[-4,,-1] ;AT LEAST 4 ARGS?
JRST IOCNV2 ;NO
MOVEI T1,IK.MTOP ;GET KWD NUMBER FOR MT OP CODE
DPB T1,[POINTR (3(L),ARGKWD)] ;STORE IN LOCAL ARG LIST
JRST IOCNV2 ;GO CONVERT UNIT, ERR, END
;SETD IS CALLED TO SET UP D FOR ALL I/O STATEMENTS.
;OPENS UNIT IF NECESSARY
;CHECKS RANDOM VS. SEQUENTIAL, FORMATTED VS. UNFORMATTED
;ARGS: A.UNIT = ADDR OF UNIT NUMBER
;RETURN: D = DDB ADDRESS
SETD: MOVE T1,%CUNIT ;GET UNIT NUMBER
MOVE U,%DDBTAB(T1) ;Get address of unit block
JUMPN U,GOTD ;ALREADY OPEN, GO CHECK STUFF
SKIPE A.REC ;TRYING TO DO RANDOM I/O?
$ECALL RR1,%ABORT ;YES. MUST SETUP RECORDSIZE IN OPEN!
MOVEI T1,ULEN ;Get length of unit block
PUSHJ P,%GTBLK ;Allocate it
MOVE U,T1
MOVEI T1,DLEN ;GET LENGTH OF DDB
PUSHJ P,%GTBLK ;ALLOCATE IT
MOVEM T1,DDBAD(U) ;SAVE DDB ADDR
MOVE T1,%CUNIT ;GET UNIT BACK
STORE T1,UNUM(U) ;SAVE UNIT NUMBER
GOTD: MOVEM U,%UDBAD ;NOW WE HAVE D AND U
MOVE D,DDBAD(U) ;Get DDB address
POPJ P,
SETBIN: LOAD T1,MODE(D) ;GET DATA MODE
JUMPN T1,%POPJ ;GOT ONE ALREADY
MOVEI T1,MD.BIN ;BINARY IS DEFAULT FOR UNFORMATTED
STORE T1,MODE(D) ;SAVE IT
MOVEI T1,FM.UNF ;SET FORM='UNFORMATTED'
STORE T1,FORM(D)
POPJ P,
SETASC: LOAD T1,MODE(D) ;GET DATA MODE
JUMPN T1,%POPJ ;GOT ONE ALREADY
MOVEI T1,MD.ASC ;DEFAULT IS ASCII
STORE T1,MODE(D) ;SAVE IT
MOVEI T1,FM.FORM ;SET FORM='FORMATTED'
STORE T1,FORM(D)
POPJ P,
OPNDDB: MOVE T1,%CUNIT ;GET UNIT NUMBER
SKIPE %DDBTAB(T1) ;DDBTAB ENTRY SET UP?
JRST TFCLR ;YES. GO CLEAR TEMP FLAGS
PUSHJ P,%OPENX ;NO. OPEN THE DDB
MOVE T1,%CUNIT ;GET UNIT NUMBER AGAIN
MOVEM U,%DDBTAB(T1) ;Store address of unit block
TFCLR: MOVX T1,D%CLR ;CLEAR ALL TEMP FLAGS
ANDCAM T1,FLAGS(D)
POPJ P,
SUBTTL BYTE I/O
COMMENT &
%IBYTE and %OBYTE are the basic routines for formatted I/O; they read or write
one byte in the current record. %RxPOS returns the current position (column
number) within a record. %SxPOS sets the current position. %IREC reads the next
record from the file. %OREC writes a record into the file.
Each open file has a record buffer which holds the current record. (This makes
T format work and makes REREAD easier.) There is one record buffer per open
file per direction.
Record buffer format:
Input:
IRBEG IRPTR
v v
--------------------------------------------------------------------
! !///////////////////////////!///////////////! !
--------------------------------------------------------------------
<--- IRCNT ---->
<---------------- IRLEN ------------------->
<-------------------------- IRSIZ -------------------------->
Output:
ORBEG ORPTR
v v
--------------------------------------------------------------------
! !///////////////////////////!///////////////! !
--------------------------------------------------------------------
<------------ ORCNT ------------>
<---------------- ORLEN* ------------------>
<-------------------------- ORSIZ -------------------------->
(*note: on output, ORLEN is not kept up to date by OBYTE, since normally
ORPTR is at the end of the record so ORLEN changes every character. ORLEN
is correct immediately after any positioning format.)
&
;ROUTINE TO READ SINGLE BYTE
;RETURN: T1 = NEXT BYTE FROM INPUT RECORD
;DESTROYS NO ACS EXCEPT T1
;NOTE: IRCNT GOING NEGATIVE IS A LEGAL CONDITION. IT MERELY
;MEANS THAT WE ARE BEYOND THE END OF THE RECORD. T-FORMAT AND
;X-FORMAT WILL SET IT NEGATIVE IF THEY GO BEYOND THE END OF
;THE RECORD.
%IBYTE: SOSGE IRCNT(D) ;DECREMENT BYTE COUNT
JRST EOR ;NONE LEFT, END OF BUFFER
ILDB T1,IRPTR(D) ;GET BYTE FROM BUFFER
POPJ P, ;DONE
EOR: IBP IRPTR(D) ;KEEP THE PNTR IN SYNCH FOR ADJBP
MOVEI T1," " ;EXTEND SHORT RECORDS WITH TRAILING SPACES
POPJ P, ;RETURN
;%IMBYT - READS MULTIPLE BYTES FROM THE RECORD BUFFER
;ARGS: T0 = # CHARS TO READ, MUST BE .LE. DESTINATION SIZE
; T3 = SIZE OF DESTINATION IN BYTES
; T4 = BYTE POINTER OF DESTINATION
%IMBYT: CAIN T3,1 ;ONE BYTE?
JRST IMONE ;YES. DO IT WITH %IBYTE
MOVN T2,T0 ;GET NEG COUNT OF CHARS TO READ
ADDB T2,IRCNT(D) ;UPDATE RECORD BYTE COUNT
JUMPL T2,IMTRUN ;PAST RECORD END, TRUNCATE INPUT
MOVE T1,T0 ;GET COUNT AGAIN
ADJBP T1,IRPTR(D) ;GET UPDATED BYTE POINTER
EXCH T1,IRPTR(D) ;SAVE UPDATED ONE, GET OLD ONE AGAIN
EXTEND T0,[EXP MOVSLJ," "] ;MOVE STRING, PAD WITH SPACES
$SNH
POPJ P,
IMTRUN: MOVE T1,T0 ;COPY # CHARS TO READ
ADJBP T1,IRPTR(D) ;UPDATE POINTER
EXCH T1,IRPTR(D) ;SAVE UPDATED ONE, GET CURRENT ONE
ADD T0,IRCNT(D) ;SHORTEN # BYTES WE GET BY COUNT BEYOND RECORD
CAIG T0,0 ;IF COUNT IS .LE. 0
DMOVE T0,[EXP 1,<POINT 7,[ASCIZ / /]>] ;USE SPACES
EXTEND T0,[EXP MOVSLJ," "] ;FILL WITH SPACES
$SNH ;SHOULD NEVER TRUNCATE
POPJ P,
IMONE: PUSHJ P,%IBYTE ;GET A BYTE
IDPB T1,T4 ;STORE IT
POPJ P,
;ROUTINE TO REREAD CURRENT BYTE
;RETURN: T1 = BYTE THAT IBYTE RETURNED ON MOST RECENT CALL
;DESTROYS NO ACS EXCEPT T1
%IBYTC: SKIPE IRLEN(D) ;NULL RECORD?
SKIPGE IRCNT(D) ;NO. PAST RECORD END?
SKIPA T1,[" "] ;YES, RETURN SPACE
LDB T1,IRPTR(D) ;NO, RETURN CURRENT CHAR
POPJ P, ;RETURN
;ROUTINE TO BACK UP INPUT BYTE POINTER
;NO ARGS
;ON RETURN, IBYTE WILL BE BACKSPACED ONE CHARACTER
;CAN BE CALLED REPEATEDLY
%IBACK: MOVNI T1,1 ;ADJUST POINTER
ADJBP T1,IRPTR(D) ;BACK 1
MOVEM T1,IRPTR(D) ;SAVE IT
AOS IRCNT(D) ;INCREMENT COUNT OF CHARS LEFT
POPJ P,
;ROUTINE TO PUT SINGLE BYTE IN FILE
;ARGS: T1 = BYTE
;DESTROYS NO ACS
%OBYTE:
LOBYTE: SETZM ORPOS(D) ;FLAG THAT WE HAVE DEPOSITED CHARS HERE
SOSGE ORCNT(D) ;DECREMENT BYTE COUNT
JRST OEXP ;BUFFER FULL, GO EXPAND IT
IDPB T1,ORPTR(D) ;STORE BYTE IN BUFFER
POPJ P, ;DONE
OEXP: SKIPE RSIZE(D) ;ANY RECORDSIZE TO LIMIT RECORD?
JRST TRUNC ;YES, TRUNCATE RECORD INSTEAD OF EXPANDING
AOS ORCNT(D) ;NO. CLEAR -1 FROM %OBYTE
PUSHJ P,%PUSHT ;SAVE T ACS
MOVM T3,ORCNT(D) ;USE DISTANCE FROM RECORD AS MINIMUM
PUSHJ P,EXPORB ;EXPAND RECORD BUFFER
PUSHJ P,%POPT ;RESTORE T ACS
JRST LOBYTE ;GO STORE BYTE IN EXPANDED BUFFER
TRUNC: IBP ORPTR(D) ;KEEP POINTER IN SYNCH FOR POSITIONING
MOVE T0,ORCNT(D) ;GET THE COUNT
CAMN T0,[-1] ;ONLY COMPLAIN THE FIRST OVERRUN
; IOERR (ETL,60,509,%,Attempt to WRITE beyond fixed-length record)
$ECALL ETL
POPJ P,
;%OMBYT - ROUTINE TO PUT A STRING OF BYTES TO THE BUFFER
;ARGS:
; T0=source count
; T1/T2=source string byte-pointer
;
;RETURNS:
;
; T1/T2=byte-pointer to last byte moved
; T3/T4/T5=trash
%OMSPC: CAIN T1,1 ;ONE SPACE?
JRST OSONE ;YES. DO IT WITH %OBYTE
MOVEI T3,(T1) ;GET # SPACES TO PAD
DMOVE T0,[EXP 1,<POINT 7,[ASCIZ / /]>] ;USE SPACES
JRST OMCOM ;JOIN COMMON CODE
%OMBYT: CAIN T0,1 ;ONE BYTE?
JRST OMONE ;YES. DO IT WITH %OBYTE
MOVE T3,T0 ;SET DESTINATION COUNT=SOURCE COUNT
OMCOM: MOVN T5,T3 ;MODIFY COUNT BEFORE ANYTHING ELSE
ADDB T5,ORCNT(D) ;SINCE T3 WILL BE ZERO AFTER MOVSLJ
JUMPGE T5,OMOK ;ENOUGH ROOM?
SKIPE RSIZE(D) ;RECORDSIZE?
JRST OMFRS ;YES. GIVE WARNING, MOVE PARTIAL STRING
PUSHJ P,%PUSHT ;SAVE T ACS
PUSHJ P,EXPORB ;EXPAND BUFFER
PUSHJ P,%POPT ;RESTORE T ACS
OMOK: MOVE T4,T3 ;GET COUNT AGAIN
ADJBP T4,ORPTR(D) ;GET UPDATED POINTER
EXCH T4,ORPTR(D) ;SAVE UPDATED ONE, GET OLD ONE BACK
EXTEND T0,[MOVSLJ
" "] ;move string
$SNH ;TRUNCATION SHOULD NOT HAPPEN
SETZM ORPOS(D) ;FLAG WE HAVE PUT CHARS AT CURRENT POSITION
POPJ P, ;we are done, return
OMFRS: MOVE T4,ORPTR(D) ;GET THE BUFFER POINTER
MOVEI T5,(T3) ;COPY THE OFFSET
ADJBP T5,ORPTR(D) ;POINT BEYOND RECORD
MOVEM T5,ORPTR(D) ;AND SAVE THE POINTER
ADD T3,ORCNT(D) ;SHORTEN DEST COUNT BY COUNT PAST RECORD
JUMPE T3,OMRE ;IF EXACTLY 0 CHARS LEFT, JUST REPORT ERROR
JUMPL T3,OMNCHR ;NOTHING TO TRANSFER IF .LE. 0
MOVEI T0,(T3) ;SET SOURCE=DEST
EXTEND T0,[EXP MOVSLJ," "] ;MOVE THE STRING
$SNH ;SHOULD NEVER TRUNCATE
OMRE: $ECALL ETL ;ATTEMPT TO WRITE BEYOND FIXED-LENGTH RECORD
OMNCHR: SETOM ORPOS(D) ;FLAG WE HAVE NOT PUT CHARS HERE
POPJ P,
OMONE: ILDB T1,T1 ;GET THE CHAR
PJRST %OBYTE ;OUTPUT IT
OSONE: MOVEI T1," " ;OUTPUT 1 SPACE
PJRST %OBYTE
EXPIRB: HRRZ T1,IRBUF(D) ;GET OLD BUFFER PNTR-1
ADDI T1,1 ;CORRECT IT
MOVE T2,IRBLN(D) ;GET OLD LENGTH IN BYTES
SETZ T3, ;NO MINIMUM SIZE
PUSHJ P,EXPRB ;EXPAND AND MOVE
HRRZ T2,IRBUF(D) ;GET OLD BUFFER ADDR-1
SUBI T2,-1(T1) ;GET OLD-NEW
MOVN T2,T2 ;GET NEW-OLD
ADDM T2,IRPTR(D) ;MOVE PNTR TO NEW BUFFER
SUBI T1,1 ;POINT AT PREVIOUS WORD
HXL T1,BYTPT(D) ;MAKE BYTE PNTR TO BEG BUFFER
MOVEM T1,IRBUF(D) ;STORE NEW BUFFER ADDR
MOVE T4,IRBLN(D) ;GET OLD SIZE AGAIN
MOVEM T3,IRBLN(D) ;STORE NEW SIZE
SUBI T3,(T4) ;RETURN SIZE LEFT IN T3
ADDM T3,IRCNT(D) ;ADD TO CURRENT COUNT
MOVE T1,ROFSET(D) ;GET OFFSET TO REAL DATA BEG
ADJBP T1,IRBUF(D) ;CALC NEW PNTR
MOVEM T1,IRBEG(D) ;SAVE IT
MOVE T1,IRBLN(D) ;GET RECORD BUFFER SIZE
SUB T1,ROFSET(D) ;AND REDUCE IT
MOVEM T1,IRSIZ(D) ;AND SAVE IT
POPJ P,
GETIRB: PUSHJ P,GETRB ;GET A NEW BUFFER
SUBI T1,1 ;POINT TO PREVIOUS WORD
HXL T1,BYTPT(D) ;MAKE BYTE PNTR TO BEG BUFFER
MOVEM T1,IRBUF(D) ;SAVE BUFFER PNTR
MOVEM T3,IRBLN(D) ;SAVE FIXED COUNT
MOVE T1,ROFSET(D) ;GET OFFSET TO REAL DATA BEG
ADJBP T1,IRBUF(D) ;CALC NEW PNTR
MOVEM T1,IRBEG(D) ;SAVE IT
MOVE T1,IRBLN(D) ;GET RECORD BUFFER SIZE
SUB T1,ROFSET(D) ;AND REDUCE IT
MOVEM T1,IRSIZ(D) ;AND SAVE IT
POPJ P,
EXPORB: HRRZ T1,ORBUF(D) ;GET OLD BUFFER PNTR-1
ADDI T1,1 ;CORRECT IT
MOVE T2,ORBLN(D) ;GET OLD LENGTH IN BYTES
PUSHJ P,EXPRB ;EXPAND AND MOVE
HRRZ T2,ORBUF(D) ;GET OLD BUFFER ADDR
SUBI T2,-1(T1) ;GET OLD-NEW
MOVN T2,T2 ;GET NEW-OLD
ADDM T2,ORPTR(D) ;MOVE PNTR TO NEW BUFFER
SUBI T1,1 ;POINT TO PREVIOUS WORD
HXL T1,BYTPT(D) ;MAKE BYTE PNTR TO BEG BUFFER
MOVEM T1,ORBUF(D) ;STORE NEW BUFFER ADDR
MOVE T4,ORBLN(D) ;GET OLD SIZE AGAIN
MOVEM T3,ORBLN(D) ;STORE NEW SIZE
SUBI T3,(T4) ;GET DIFF
ADDM T3,ORCNT(D) ;ADD TO CURRENT COUNT
MOVE T1,ROFSET(D) ;GET OFFSET TO REAL DATA BEG
ADJBP T1,ORBUF(D) ;CALC NEW PNTR
MOVEM T1,ORBEG(D) ;SAVE IT
MOVE T1,ORBLN(D) ;GET RECORD BUFFER SIZE
SUB T1,ROFSET(D) ;AND REDUCE IT
MOVEM T1,ORSIZ(D) ;AND SAVE IT
POPJ P,
GETORB: PUSHJ P,GETRB ;GET A NEW BUFFER
SUBI T1,1 ;POINT TO PREVIOUS WORD
HXL T1,BYTPT(D) ;MAKE IT A BYTE PNTR
MOVEM T1,ORBUF(D) ;SAVE BUFFER PNTR
MOVEM T3,ORBLN(D) ;SAVE COUNT
MOVE T1,ROFSET(D) ;GET OFFSET TO REAL DATA BEG
ADJBP T1,ORBUF(D) ;CALC NEW PNTR
MOVEM T1,ORBEG(D) ;SAVE IT
MOVE T1,ORBLN(D) ;GET RECORD BUFFER SIZE
SUB T1,ROFSET(D) ;AND REDUCE IT
MOVEM T1,ORSIZ(D) ;AND SAVE IT
POPJ P,
;EXPRB - ROUTINE TO EXPAND A RECORD BUFFER
;CALL:
; T1 = ADDR OF OLD BUFFER
; T2 = OLD LENGTH IN BYTES
; T3 = MINIMUM ADDITIONAL SIZE IN BYTES
;RETURN:
; T1 = ADDR OF START OF MOVED RECORD BUFFER
; T2 = ADDR OF FIRST FREE WORD IN MOVED RECORD BUFFER
; T3 = NUMBER OF BYTES IN MOVED RECORD BUFFER
EXPRB: MOVEI T4,(T2) ;COPY OLD SIZE
LSH T4,1 ;DOUBLE IT
ADD T4,T3 ;ADD MINIMUM SIZE
IDIV T2,BPW(D) ;GET # WORDS IN OLD BUFFER
MOVEI T3,(T4) ;COPY NEW SIZE
IDIV T3,BPW(D) ;GET # WORDS IN NEW BUFFER
PUSHJ P,%MVSPC ;MOVE TO BIGGER BUFFER, FILL WITH SPACES
MOVEI T1,(T1) ;LOCAL ADDR
IMUL T3,BPW(D) ;CONVERT NEW # WORDS TO CHARS
POPJ P, ;RETURN
;GETRB - GET A RECORD BUFFER
;RETURN:
; T1 = ADDR OF RECORD BUFFER
; T2 = COPY OF T1
; T3 = SIZE IN BYTES
GETRB: SKIPN T1,FRSIZB(D) ;IF FIXED-LENGTH, USE IT
MOVEI T1,LRECBF ;VARIABLE, USE MINIMUM SIZE
ADD T1,BPW(D) ;ROUND UP TO WORDS
SUBI T1,1
IDIV T1,BPW(D) ;GET # WORDS
PUSHJ P,%GTSPC ;GET BLOCK, FILL WITH SPACES
MOVE T2,T1 ;COPY ADDR
SKIPN T3,FRSIZB(D) ;GET LENGTH AGAIN
MOVEI T3,LRECBF
POPJ P,
SUBTTL INPUT
;%IREC - INITIAL RECORD INPUT. SETS UP THE BUFFER (IF NECESSARY) AND
;GOES TO THE APPROPRIATE ROUTINE. CALLED ONLY FROM FINGO.
%IREC: SKIPN IRBUF(D) ;ANY BUFFER YET?
PUSHJ P,GETIRB ;NO. ALLOCATE THE BUFFER
SETOM LSNUM(D) ;SET UP ILLEGAL LINE SEQUENCE NUMBER
AOS CREC(D) ;INCREMENT RECORD NUMBER
LOAD T1,INDX(D) ;GET DEV INDEX
PJRST IDSP(T1) ;DO DEVICE-DEPENDENT INPUT
;%IRECS IS THE SAME AS %IREC, EXCEPT IT IS ONLY CALLED FROM WITHIN
;A FORMAT (FOR "/" AND INDEFINITE REPEAT) AND FOR MULTIRECORD INPUT
;IN NAMELIST AND LIST-DIRECTED I/O.
%IRECS: SKIPN IRBUF(D) ;ANY BUFFER YET?
PUSHJ P,GETIRB ;NO. ALLOCATE THE BUFFER
SETOM LSNUM(D) ;SET UP ILLEGAL LINE SEQUENCE NUMBER
AOS CREC(D) ;INCREMENT RECORD NUMBER
LOAD T1,INDX(D) ;GET DEV INDEX
PJRST IDSPS(T1) ;DO DEVICE-DEPENDENT INPUT
;IRSET - CALLED AFTER READING THE DATA FOR ALL "EXTERNAL" DEVICES
;TO SET UP THE POINTER AND COUNT FOR READING WITH %IBYTE.
IRSET: MOVE T1,IRBEG(D) ;GET RECORD BUFFER PNTR
MOVEM T1,IRPTR(D) ;STORE INITIALIZED BYTE PTR
SKIPE IRCNT(D) ;ANY CHARS IN RECORD?
POPJ P, ;YES. WE'RE DONE
MOVE T0,FLAGS(D) ;Get current DDB flags
TXNE T0,D%END ;ZERO CHARS. EOF ALSO?
$ECALL EOF,%ABORT ;YES. REPORT IT AND DIE
POPJ P, ;NO. JUST A NULL RECORD
REREAD: MOVE T1,IRBEG(D)
MOVEM T1,IRPTR(D)
MOVE T1,IRLEN(D) ;REREAD. SETUP PNTR/COUNT WITH OLD DATA
MOVEM T1,IRCNT(D)
JUMPN T1,%POPJ ;NOT EOF IF WE HAVE CHARS
MOVE T0,FLAGS(D)
TXNE T0,D%END ;END OF FILE?
$ECALL EOF,%ABORT ;YES. REPORT IT AND DIE
POPJ P, ;Return
;ALL DEVICE-DEPENDENT INPUT ROUTINES HAVE THE SAME CALLING SEQUENCE:
;ARGS: IRBEG = BYTE POINTER TO START OF RECORD BUFFER
; IRSIZ = NUMBER OF BYTES IN RECORD BUFFER
;RETURN: NEXT RECORD FROM FILE READ INTO RECORD BUFFER
; IRCNT = NUMBER OF BYTES FOUND IN RECORD BUFFER
IDSP: JRST TIREC ;TTY
JRST DIREC ;DISK
JRST XIREC ;MTA
JRST XIREC ;OTHER
JRST DECODE ;DECODE
JRST IFIN ;INTERNAL FILE INPUT
IDSPS: JRST TIRECS ;TTY
JRST DIREC ;DISK
JRST XIREC ;MTA
JRST XIREC ;OTHER
JRST DECODE ;DECODE
JRST IFIN ;INTERNAL FILE INPUT
IF20,<
;TTY
;TIREC - FOR INITIAL INPUT, EOF IS ALWAYS CLEARED FOR TTY, SINCE IT
;IS DEFINED AS A LINE-BY-LINE EOF (IS NOT "STICKY").
;TIRECS - FOR "/" FORMAT, INDEFINITE REPEAT, AND MULTIRECORD INPUT,
;EOF (CONTROL-Z) IS STICKY, AND WILL GET AN EOF RETURN.
TIREC: MOVX T0,D%END ;CLEAR EOF FOR TTY'S
ANDCAM T0,FLAGS(D)
TIRECS: PUSHJ P,T20INP ;END= STAYS ON
PJRST IRSET ;AND RETURNS IMMEDIATELY IF EOF
T20INP: SETZM IRCNT(D) ;CLEAR CHAR COUNT IN CASE EOF
SETZM IRLEN(D) ;AND RECORD LENGTH
MOVE T0,FLAGS(D) ;JUST LEAVE IF EOF
TXNE T0,D%END
POPJ P,
TXNN T0,D%SEOL ;SUPPRESS CR OR LF?
PUSHJ P,%OCRLF ;NO. OUTPUT CRLF
MOVEI T1,.RDBRK ;SET TEXTI BLOCK LENGTH
MOVEM T1,TXIBLK+.RDCWB
MOVX T1,RD%CRF+RD%JFN+RD%BBG ;SUPPRESS CR, READ FROM JFNS, BFP GIVEN
MOVEM T1,TXIBLK+.RDFLG ;STORE FLAGS
LOAD T1,IJFN(D) ;GET JFN
HRLI T1,(T1) ;IN BOTH HALVES
MOVEM T1,TXIBLK+.RDIOJ ;STORE IT
MOVE T1,IRBEG(D) ;GET RECORD BUFFER PNTR
MOVEM T1,TXIBLK+.RDDBP ;STORE DEST BYTE POINTER
MOVEM T1,TXIBLK+.RDBFP ;AND BEGINNING-OF-BUFFER POINTER
MOVE T1,IRSIZ(D) ;GET RECORD BUFFER LENGTH
MOVEM T1,TXIBLK+.RDDBC ;STORE DEST BYTE COUNT
SETZM TXIBLK+.RDBFP ;NO WAKEUP ON ^U, ^W EDITING
MOVE T1,G.PRP ;SET POINTER TO PROMPT STRING
MOVEM T1,TXIBLK+.RDRTY
MOVEI T1,TXIBRK ;POINT TO BREAK MASK
MOVEM T1,TXIBLK+.RDBRK ;STORE IT
TCONT: MOVEI T1,TXIBLK ;POINT TO BLOCK
TEXTI% ;READ A LINE
JSHALT ;SHOULD NOT FAIL
MOVE T1,TXIBLK+.RDFLG ;GET TEXTI FLAGS
TXNN T1,RD%BTM ;INPUT TERMINATED BY BREAK CHAR?
JRST TEXP ;NO, EXPAND BUFFER AND CONTINUE
MOVX T0,D%END ;Get flag to set if CTRL-Z seen.
LDB T1,TXIBLK+.RDDBP ;GET TERMINATING CHAR
CAIE T1,32 ;^Z?
MOVX T0,D%SEOL ;NO. SUPPRESS NEXT LEADING EOL
IORM T0,FLAGS(D) ;Yes, set end-of-file
SETZM G.PRP ;CLEAR PROMPT STRING FOR NEXT TIME
AOS T3,TXIBLK+.RDDBC ;RETURN COUNT OF LEFTOVER BYTES IN BUFFER
;DISCARDING BREAK CHARACTER
MOVE T1,IRSIZ(D) ;GET SIZE OF RECORD BUFFER
SUBI T1,(T3) ;CALC # CHARS IN RECORD
MOVEM T1,IRCNT(D) ;SAVE FOR INPUT
MOVEM T1,IRLEN(D) ;SAVE LENGTH
POPJ P, ;DONE
TEXP: MOVE T1,TXIBLK+.RDDBP ;GET UPDATED POINTER
MOVEM T1,IRPTR(D) ;SAVE FOR EXPANSION
MOVE T1,TXIBLK+.RDDBC ;GET UPDATED COUNT
MOVEM T1,IRCNT(D) ;SAVE FOR EXPANSION
PUSHJ P,EXPIRB ;EXPAND RECORD BUFFER
MOVE T1,IRBEG(D)
MOVEM T1,TXIBLK+.RDBFP ;SET NEW POINTER TO START OF BUFFER
MOVE T1,IRPTR(D)
MOVEM T1,TXIBLK+.RDDBP ;SET POINTER TO DEST STRING
MOVE T1,IRCNT(D)
MOVEM T1,TXIBLK+.RDDBC ;SET BYTE COUNT OF DEST STRING
JRST TCONT ;DO ANOTHER TEXTI TO CONTINUE INPUT
;STILL IF20
;TEXTI BREAK TABLE FOR STANDARD FORTRAN CHAR SET
TXIBRK: 1B<^O12>+1B<^O13>+1B<^O14>+1B<^O32> ;BREAK ON LF, VT, FF, ^Z
0 ;AND NOTHING ELSE
0
0
SEGMENT DATA
TXIBLK: BLOCK 1+.RDBRK ;TEXTI ARG BLOCK
SEGMENT CODE
>;END IF20
IF10,<
TIREC: MOVX T0,D%END ;CLEAR EOF FOR TTY'S
ANDCAM T0,FLAGS(D) ;Store updated flags
TIRECS: PUSHJ P,T10INP ;DO TOPS-10 TTY INPUT
PJRST IRSET ;AND GO DO SETUP
T10INP: SETZM IRCNT(D) ;CLEAR CHAR COUNT IN CASE EOF
SETZM IRLEN(D) ;AND RECORD LENGTH
MOVE T0,FLAGS(D) ;ARE WE AT EOF?
TXNE T0,D%END
POPJ P, ;YES. GO NO FURTHER
TXNN T0,D%SEOL ;SUPPRESS CRLF?
PUSHJ P,%OCRLF ;NO. OUTPUT CRLF
MOVX T0,D%SEOL ;SUPPRESS NEXT CRLF
IORM T0,FLAGS(D)
MOVE T1,IRBEG(D) ;GET POINTER
MOVEM T1,IRPTR(D) ;SAVE FOR TRANSFER
MOVE T1,IRSIZ(D) ;AND COUNT
MOVEM T1,IRCNT(D)
TLP0: SOSL ICNT(D) ;ANY MORE BYTES?
JRST TLPX1 ;NO. GET MORE
PUSHJ P,IMAP
JRST DIEOR ;GOT EOF
JRST TLP0 ;KEEP IN SYNCH
TLPX1: ILDB T1,IPTR(D) ;GET A CHAR
JUMPE T1,TLP0 ;SKIP IT IF NULL
JRST TLPGTC ;USE IT IF NOT NULL
TLP: SOSL ICNT(D) ;ANY MORE BYTES?
JRST TLPX2 ;YES
PUSHJ P,IMAP ;NO
JRST DIEOR ;GOT EOF
JRST TLP ;KEEP IN SYNCH!
TLPX2: ILDB T1,IPTR(D) ;GET A BYTE
TLPGTC: CAIGE T1," " ;CHECK FOR SPECIAL BYTE
JRST TCHKEL ;SPECIAL
TDPB: SKIPE IRCNT(D) ;ROOM IN RECORD BUFFER?
JRST TDPB2 ;YES
PUSHJ P,EXPIRB ;NO. EXPAND RECORD BUFFER
LDB T1,IPTR(D) ;AND GET THE CHAR AGAIN
TDPB2: SOS IRCNT(D) ;DECR RECORD BYTE COUNT
IDPB T1,IRPTR(D) ;DEPOSIT BYTE IN RECORD BUFFER
JRST TLP ;BACK FOR MORE
TCHKEL: CAIN T1,15 ;CARRIAGE RETURN?
JRST GOTCR ;YES
CAIG T1,14 ;STANDARD EOF CHARS ARE 12-14 (LF,VT,FF)
CAIGE T1,12 ;EOL CHAR?
JRST NOTEOL ;NO. CHECK FOR TTY CONTROL-Z
JRST DIEOR ;YES. DECR COUNT AND END IT ALL
NOTEOL: CAIE T1,33 ;ESCAPE?
JRST NOTESC ;NO
OUTSTR %CRLF ;YES. OUTPUT A CRLF
JRST DIEOR ;AND END THE LINE
NOTESC: CAIE T1,32 ;^Z?
JRST TDPB ;NO. PASS IT THROUGH
PUSHJ P,IMAP ;YES. GET ANOTHER BUFFER
JRST DIEOR ;SHOULD GET EOF
$SNH ;UNLESS TOPS-10 CHANGES
>;END IF10
DIREC:
XIREC: PUSHJ P,CIREC ;DO COMMON INPUT RECORD CODE
PJRST IRSET ;AND SETUP FOR GETTING BYTES FROM IT
CIREC: SETZM IRCNT(D) ;CLEAR CHAR COUNT IN CASE EOF
SETZM IRLEN(D) ;AND RECORD LENGTH
MOVE T1,FLAGS(D) ;ARE WE AT EOF?
TXNE T1,D%END
POPJ P, ;YES. GO NO FURTHER
SKIPE FRSIZW(D) ;FIXED-LENGTH, WORD-ALIGNED RECORDS?
JRST INBLT ;YES. READ WITH BLT
SKIPE FRSIZB(D) ;FIXED-LENGTH, NON-WORD-ALIGNED RECORDS?
JRST INMSLJ ;YES. READ WITH MOVSLJ
MOVE T1,IRBEG(D) ;GET POINTER
MOVEM T1,IRPTR(D) ;SAVE FOR TRANSFER
MOVE T1,IRSIZ(D) ;AND COUNT
MOVEM T1,IRCNT(D)
NULP: SOSL ICNT(D) ;ANY CHARS IN BUFFER?
JRST NULCHK ;YES
PUSHJ P,IMAP ;NO
JRST DIEOR ;GOT EOF
JRST NULP ;KEEP IN SYNCH!
NULCHK: ILDB T1,IPTR(D) ;GET A CHAR
JUMPE T1,NULP ;SKIP NULLS
LOAD T2,MODE(D) ;GET FILE MODE
CAIE T2,MD.ASL ;LINED?
JRST NULDEP ;NO. GO DEPOSIT CHAR
HRRZ T2,IPTR(D) ;YES. GET LOCAL ADDR OF BUFFER
MOVE T2,(T2) ;GET WORD
TRNN T2,1 ;LINE NUMBER?
JRST NULDEP ;NO. GO DEPOSIT CHAR
MOVEM T2,LSNUM(D) ;SAVE IT
AOS IPTR(D) ;YES. INCR BUFFER PNTR PAST IT
MOVNI T2,5 ;AND DECR THE CHAR COUNT
ADDB T2,ICNT(D)
JUMPG T2,CHKTAB ;GO CHECK FOR TAB IF STILL CHARS
PUSHJ P,IMAP ;GET NEW BUFFER IF NOT
JRST DIEOR ;GOT EOF
CHKTAB: SOS ICNT(D) ;DECR COUNT
ILDB T1,IPTR(D) ;GET A CHAR
CAIN T1," " ;TAB?
JRST INSLP ;YES. SKIP IT
NULDEP: CAIG T1,15 ;TERMINATOR?
CAIGE T1,12
JRST .+2 ;NO. GO DEPOSIT CHAR
JRST CHKEOL ;YES. GO CHECK IT
IDPB T1,IRPTR(D) ;SAVE THE FIRST CHAR
SOS IRCNT(D) ;DECR THE COUNT
INSLP: MOVE T0,ICNT(D) ;GET BUFFER COUNT
JUMPG T0,INSOK ;IF SOME CHARS, CONTINUE
PUSHJ P,IMAP ;IF NOT, GET SOME
JRST DIEOR ;GOT EOF
MOVE T0,ICNT(D) ;GET COUNT AGAIN
INSOK: MOVE T1,IPTR(D) ;GET PNTR
MOVE T3,IRCNT(D) ;GET RECORD ROOM AVAILABLE
MOVE T4,IRPTR(D) ;GET RECORD PNTR
CAMGE T0,T3 ;SOURCE .GE. DEST?
MOVE T3,T0 ;NO. RESTRICT DEST TO SOURCE TO PREVENT FILL
MOVEM T3,LOCSIZ ;SAVE IT
TLO T0,(1B0) ;TURN ON TRANSLATION
EXTEND T0,[EXP <MOVST ASCTAB>," "] ;MOVE THE STRING
NOP ;DON'T TREAT TRUNCATION SPECIAL
TLZ T0,777000 ;TURN OFF ALL BUT # CHARS
MOVEM T0,ICNT(D) ;STORE NEW COUNT
MOVEM T1,IPTR(D) ;SAVE UPDATED PNTR
MOVEM T4,IRPTR(D) ;AND RECORD PNTR
MOVN T2,LOCSIZ ;GET # CHARS WE WANTED TO TRANSFER
ADD T2,T3 ;CALC ACTUAL # CHARS TRANSFERRED
ADDB T2,IRCNT(D) ;AND RECORD COUNT
JUMPG T3,CHKEOL ;IF WE TERMINATED, CHECK THE EOL CHAR
JUMPG T2,INSLP ;IF WE TRUNCATED, WE NEED MORE INPUT
PUSHJ P,EXPIRB ;RECORD COUNT NOW ZERO - EXPAND THE BUFFER
JRST INSLP ;AND CONTINUE
CHKEOL: LDB T1,IPTR(D) ;GET THE TERMINATOR CHARACTER
CAIE T1,15 ;CR?
JRST DIEOR ;NO. END OF RECORD
GOTCR: DMOVE T1,IPTR(D) ;GET PNTR/COUNT
CRLP: DMOVEM T1,IPTR(D) ;SAVE PNTR/COUNT
SOJGE T2,CRX2 ;DECR COUNT. OK IF CHARS LEFT
PUSHJ P,IMAP ;NO. GET A BUFFERFUL
JRST DIEOR ;GOT EOF
JRST GOTCR ;KEEP IN SYNCH
CRX2: ILDB T3,T1 ;GET A CHAR
JUMPE T3,CRLP ;SKIP NULLS
CAIN T3,15 ;ANOTHER CARRIAGE RETURN?
JRST CRLP ;YES. IGNORE IT
CAIG T3,14 ;VERT MOTION CHAR?
CAIGE T3,12
JRST DIEOR ;NO. DATA
DMOVEM T1,IPTR(D) ;YES. SAVE UPDATED PNTR/COUNT
DIEOR: MOVE T1,IRSIZ(D) ;GET RECORD BUFFER SIZE
SUBB T1,IRCNT(D) ;GET # CHARS IN RECORD
MOVEM T1,IRLEN(D) ;SAVE LENGTH
POPJ P,
ASCTAB: BYTE (18)0,1,2,3,4,5,6,7
BYTE (18)10,11,100012,100013,100014,100015,16,17
BYTE (18)20,21,22,23,24,25,26,27,30,31,32,33,34,35,36,37
BYTE (18)40,41,42,43,44,45,46,47,50,51,52,53,54,55,56,57
BYTE (18)60,61,62,63,64,65,66,67,70,71,72,73,74,75,76,77
BYTE (18)100,101,102,103,104,105,106,107
BYTE (18)110,111,112,113,114,115,116,117
BYTE (18)120,121,122,123,124,125,126,127
BYTE (18)130,131,132,133,134,135,136,137
BYTE (18)140,141,142,143,144,145,146,147
BYTE (18)150,151,152,153,154,155,156,157
BYTE (18)160,161,162,163,164,165,166,167
BYTE (18)170,171,172,173,174,175,176,177
;INPUT OF FIXED-LENGTH, WORD-ALIGNED RECORDS IS ACCOMPLISHED
;BY READING WORDS DIRECTLY FROM THE FILE, REGARDLESS OF CONTENT.
;THE RECORD SIZE PARAMETERS ARE THEN SET FROM THE PRESET RECORDSIZE.
INBLT: MOVE T1,FRSIZW(D) ;GET RECORDSIZE
MOVEM T1,LOCSIZ ;SAVE FOR TRANSFER
MOVE T1,IRBUF(D) ;INIT RECORD POINTER
MOVEM T1,IRPTR(D)
INBLP: MOVE T4,ICNT(D) ;GET BUFFER COUNT
IDIV T4,BPW(D) ;GET # WORDS
JUMPG T4,INBOK ;OK IF SOME
PUSHJ P,IMAP ;GET MORE IF NONE
$ECALL EOF,%ABORT ;EOF. REPORT IT IMMEDIATELY!
MOVE T4,ICNT(D) ;GET NEW COUNT
IDIV T4,BPW(D) ;GET # WORDS
INBOK: MOVE T3,LOCSIZ ;GET # WORDS TO TRANSFER
CAILE T3,(T4) ;.GT. NUMBER OF WORDS IN BUFFER
MOVEI T3,(T4) ;YES. USE THE SMALLER ONE
HRRZ T5,IRPTR(D) ;GET RECORD ADDR-1
ADDI T5,1 ;CORRECT IT
HRRZ T1,IPTR(D) ;GET INPUT BUFFER ADDR-1
HRLZI T1,1(T1) ;NOW GET ITS ADDRESS AS SOURCE
HRRI T1,(T5) ;DESTINATION IS RECORD BUFFER
ADDI T5,-1(T3) ;GET FINAL DEST
BLT T1,(T5) ;TRANSFER THE WORDS
ADDM T3,IRPTR(D) ;UPDATE RECORD PNTR
ADDM T3,IPTR(D) ;AND BUFFER POINTER
SUBI T4,(T3) ;AND BUFFER WORD COUNT
IMUL T4,BPW(D) ;GET BYTES LEFT
MOVEM T4,ICNT(D) ;SAVE IT
MOVNI T3,(T3) ;GET NEG # WORDS TRANSFERRED
ADDB T3,LOCSIZ ;UPDATE TOTAL WORD COUNT
JUMPG T3,INBLP ;IF MORE, TRY FOR MORE
MOVE T1,RSIZE(D) ;SETUP COUNT AND LENGTH
MOVEM T1,IRCNT(D)
MOVEM T1,IRLEN(D)
MOVE T1,FLAGS(D) ;GET DDB FLAGS
TXNN T1,D%RAN ;RANDOM FILE?
POPJ P, ;NO. DON'T CHECK CONTENTS
MOVN T1,FRSIZW(D) ;GET NEG # WORDS IN RECORD
HRLZI T1,(T1) ;IN LEFT HALF
HRR T1,IRBUF(D) ;CREATE AOBJN POINTER TO RECORD-1
ADDI T1,1 ;CORRECT IT
MOVE T3,(T1) ;GET 1ST WORD
LOAD T2,MODE(D) ;GET DATA MODE
CAIN T2,MD.ASL ;LINED?
MOVEM T3,LSNUM(D) ;YES. SAVE LSN
INBCHK: SKIPN (T1) ;WORD NON-ZERO?
AOBJN T1,INBCHK ;ZERO. TRY ANOTHER
JUMPL T1,%POPJ ;IF STILL IN RECORD, WE'RE OK
$ECALL RNR,%ABORT ;IF NOT, RECORD NOT WRITTEN
;INPUT OF FIXED-LENGTH NON-WORD-ALIGNED RECORDS IS READ WITHOUT
;REGARD TO DATA CONTENT WITH MOVSLJ. EXACTLY RSIZE CHARACTERS ARE
;READ INTO THE RECORD BUFFER. THE RECORD LENGTH PARAMETERS ARE
;SET TO THE PRESET RECORDSIZE.
;FOR NOW, RANDOM RECORDS ARE ALWAYS WORD-ALIGNED, AND THEREFORE
;ARE NOT READ HERE. IF THEY EVER ARE, WE MUST ADD A CHECK AT THE
;END FOR RECORD NOT WRITTEN (ALL CHARACTERS NULL). FOR EFFICIENCY,
;THIS WOULD PROBABLY REQUIRE THAT THE INITIAL RECORD BE NULLS,
;RATHER THAN SPACES, SO THAT WE CAN CHECK WITH AOBJN.
INMSLJ: MOVE T1,IRBLN(D) ;GET RECORD BUFFER LENGTH
MOVEM T1,IRCNT(D)
MOVE T1,IRBUF(D) ;AND PNTR
MOVEM T1,IRPTR(D)
INMSLP: MOVE T0,ICNT(D) ;GET COUNT
JUMPG T0,INMSOK ;OK IF NON-ZERO
PUSHJ P,IMAP ;NO CHARS. GET A BUFFERFUL
$ECALL EOF,%ABORT ;EOF. REPORT IT IMMEDIATELY!
MOVE T0,ICNT(D) ;GET UPDATED COUNT
INMSOK: MOVE T1,IPTR(D) ;GET BUFFER PNTR
MOVE T3,IRCNT(D) ;GET RECORD PNTR/COUNT
MOVE T4,IRPTR(D)
CAIGE T0,(T3) ;SOURCE .GE. DEST?
MOVE T3,T0 ;NO. RESTRICT DEST TO PREVENT FILL
MOVNI T2,(T3) ;UPDATE RECORD COUNT, AS MOVSLJ CLEARS IT
ADDM T2,IRCNT(D)
EXTEND T0,[EXP <MOVSLJ>,0] ;MOVE RECORD
NOP ;TRUNCATION HAPPENS MOST OF THE TIME
MOVEM T0,ICNT(D) ;SAVE UPDATED WINDOW COUNT
MOVEM T1,IPTR(D) ;AND POINTER
MOVEM T4,IRPTR(D)
SKIPE IRCNT(D) ;DID WE FINISH?
JRST INMSLP ;NO. TRY AGAIN
MOVE T1,RSIZE(D) ;SETUP RECORD LENGTH AND COUNT
MOVEM T1,IRLEN(D)
MOVEM T1,IRCNT(D)
POPJ P,
IMAP: MOVE T0,FLAGS(D) ;Get DDB flags
TXNE T0,D%END ;EOF ALREADY?
POPJ P, ;YES. NON-SKIP RETURN
PUSHJ P,INXTW ;NO. GET NEXT WINDOW
MOVE T0,FLAGS(D) ;Get DDB flags
TXNN T0,D%END ;IF FILE DID NOT END,
AOS (P) ;SKIP RETURN
POPJ P, ;ELSE DONE
;DECODE
DECINI: MOVE T1,A.HSA ;GET STRING ADDR
$BLDBP T1 ;Build 7-bit byte ptr.
MOVE T2,T.HSA ;GET ARRAY TYPE
CAIN T2,TP%CHR ;CHARACTER?
MOVE T1,@A.HSA ;YES. GET THE POINTER
MOVEM T1,IRPTR(D)
MOVEM T1,IRBUF(D)
MOVEM T1,IRBEG(D)
SKIPG T1,@A.HSL ;GET RECORD LENGTH
$ECALL SLN,%ABORT ;RECORD LENGTH NOT POSITIVE
MOVEM T1,IRCNT(D) ;SAVE CHAR COUNT
MOVEM T1,RSIZE(D) ;AND RECORD SIZE
MOVEM T1,IRBLN(D) ;AND REC BUFFER LENGTH
MOVEM T1,IRSIZ(D)
MOVEM T1,BYTN(D) ;SET NEXT RECORD START
MOVEM T1,IRLEN(D) ;AND RECORD LENGTH
POPJ P, ;RETURN
DECODE: MOVE T1,BYTN(D) ;GET NEXT RECORD START
ADJBP T1,IRBUF(D) ;MOVE POINTER TO NEXT ENTRY
MOVEM T1,IRBEG(D) ;SAVE PNTR TO BEG OF RECORD
MOVEM T1,IRPTR(D) ;SAVE MOVING POINTER
MOVE T1,IRSIZ(D) ;GET ENTRY SIZE
MOVEM T1,IRCNT(D) ;SAVE IT
ADDM T1,BYTN(D) ;SET TO POINT TO NEXT RECORD
POPJ P,
;INTERNAL FILES - INPUT SETUP
;SETUP THE FOROTS INTERNAL BUFFER POINTER/COUNT TO
;THE CHARACTER VARIABLE/ARRAY. IRBUF(D) ALWAYS CONTAINS
;A POINTER TO THE BEGINNING OF THE ENTIRE VARIABLE/ARRAY.
;BYTN IS UPDATED AT THE INITIALIZATION AND EACH READ
;TO POINT TO THE RELATIVE POSITION (IN BYTES) OF THE
;NEXT RECORD.
IFINI: MOVE T1,A.UNIT ;GET ADDRESS OF DESCRIPTOR
MOVE T2,(T1) ;GET BYTE POINTER
MOVEM T2,IRBUF(D) ;SAVE AS RECORD BUFFER POINTER
MOVEM T2,IRBEG(D)
MOVEM T2,IRPTR(D) ;AND MOVING POINTER
MOVE T2,1(T1) ;GET VARIABLE ENTRY SIZE
MOVEM T2,IRBLN(D) ;SAVE AS BUFFER LENGTH
MOVEM T2,IRSIZ(D)
MOVEM T2,IRCNT(D) ;AND MOVING COUNT
MOVEM T2,IRLEN(D) ;AND RECORD LENGTH
MOVEM T2,RSIZE(D) ;AND RECORDSIZE
MOVEM T2,BYTN(D) ;AND START OF NEXT RECORD
MOVE T3,@A.HSL ;GET TOTAL # CHARS IN ARRAY
SKIPN A.HSL ;UNLESS THERE IS NO KEYWORD
MOVE T3,1(T1) ;NONE. GET IT FROM THE DESCRIPTOR
MOVEM T3,EOFN(D) ;SAVE IT
JUMPG T3,%POPJ ;NON-ZERO IS OK
$ECALL ICE,%ABORT ;ILLEGAL CHARACTER EXPRESSION
;INPUT
;UPDATE THE POINTER TO POINT TO THE NEXT ARRAY ENTRY.
;IF MORE THAN ONE RECORD FOR A SCALAR OR EXPRESSION, OR
;BEYOND THE END OF AN ARRAY, REPORT END-OF-FILE.
IFIN: MOVE T1,BYTN(D) ;GET NEXT RECORD START
CAML T1,EOFN(D) ;END OF ARRAY?
$ECALL EOF,%ABORT ;YES. REPORT END OF FILE
ADJBP T1,IRBUF(D) ;MOVE POINTER TO NEXT ENTRY
MOVEM T1,IRBEG(D) ;SAVE POINTER TO BEG OF RECORD
MOVEM T1,IRPTR(D) ;SAVE MOVING POINTER
MOVE T1,IRSIZ(D) ;GET ENTRY SIZE
MOVEM T1,IRCNT(D) ;SAVE IT
ADDM T1,BYTN(D) ;SET TO POINT TO NEXT RECORD
POPJ P,
SUBTTL OUTPUT
;%OREC IS CALLED AT THE FIN CALL AT THE END OF ALL FORMATTED I/O WRITES.
;%ORECS IS CALLED FROM FORFMT (FOR "/" FORMAT) AND NMLST/LDIO (TO
;OUTPUT AN INTERMEDIATE RECORD). %ORECS USES CODSP FOR ITS DISPATCH
;TABLE, WHICH, FOR ENCODE AND INTERNAL FILE OUTPUT,
;CALLS ENCODE OR IFOUT TO UPDATE THE RECORD POINTER/COUNT.
%ORECS: AOS CREC(D) ;COUNT RECORD
LOAD T1,INDX(D) ;GET DEVICE INDEX
PJRST ODSPS(T1) ;OUTPUT THE RECORD, CHECK INT FILE OVERRUN
%OREC: AOS CREC(D) ;COUNT RECORD
LOAD T1,INDX(D) ;GET DEV INDEX
PJRST ODSP(T1) ;OUTPUT THE RECORD, AS APPROPRIATE FOR DEV
PUTSTR: LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.TTY ;TTY?
JRST DOSTR ;NO. OTHER DEVICE
JRST TOSTR ;YES.
;ORINI - RESETS THE POINTER/COUNT TO THE BEGINNING OF THE
;BUFFER FOR ALL "EXTERNAL" DEVICES (E.G. DISK, TTY)
ORINI: SETZM ORLEN(D) ;CLEAR RECORD LENGTH
SETZM ORPOS(D) ;CLEAR VIRTUAL POS
MOVE T1,ORBEG(D) ;RESET BYTE POINTER
MOVEM T1,ORPTR(D)
MOVE T2,ORSIZ(D) ;RESET BYTE COUNT
MOVEM T2,ORCNT(D)
HRRZ T1,ORBUF(D) ;POINT TO RECORD BUFFER-1
ADDI T1,1 ;CORRECT IT
MOVE T3,SPCWD(D) ;GET A WORD OF SPACES
MOVEM T3,(T1) ;SET THE 1ST WORD
MOVE T2,ORBLN(D) ;GET FULL BUFFER SIZE
ADD T2,BPW(D) ;ROUND UP TO WORDS
SUBI T2,1
IDIV T2,BPW(D) ;GET # WORDS IN RECORD
CAIG T2,1 ;MORE THAN 1?
POPJ P, ;NO. WE'RE DONE
ADDI T2,-1(T1) ;GET END WORD ADDR
HRLI T1,(T1) ;SETUP FOR BLT
ADDI T1,1
BLT T1,(T2) ;FILL ENTIRE RECORD WITH SPACES
POPJ P, ;DONE, READY FOR NEXT OUTPUT
ODSP: JRST TOREC
JRST DOREC
JRST XOREC
JRST XOREC
POPJ P,
POPJ P,
ODSPS: JRST TORECS ;TTY
JRST DORECS ;DISK
JRST XORECS ;MTA
JRST XORECS ;OTHER
JRST ENCODE ;DECODE
JRST IFOUT ;INTERNAL FILE OUTPUT
;ERROR MESSAGE OUTPUT
;ARGS: T1 = ADDRESS OF ASCIZ MESSAGE STRING
%EOREC: MOVEM T1,ERPTR ;SAVE MESSAGE POINTER
SKIPN U.ERR ;POINT TO ERR DDB
JRST ETTY ;NONE, USE PSOUT
PUSH P,U ;SAVE U AND D
PUSH P,D
SETZ F, ;NO FLAGS, PLEASE
MOVE U,U.ERR ;GET UNIT BLOCK ADDR
PUSH P,U.ERR ;RECURSIVE ERRS GO TO TTY
SETZM U.ERR
MOVE D,DDBAD(U) ;Set up D
PUSHJ P,%SETOUT ;Set file open for output
MOVE T1,FLAGS(D) ;GET DDB FLAGS
TXNN T1,D%SEOL ;SUPPRESS LEADING CRLF?
PUSHJ P,%OCRLF ;NO. MUST WANT ONE
SETZ T2, ;CLEAR CHAR COUNT
MOVE T3,ERPTR ;GET ERROR POINTER
EOLP: ILDB T1,T3 ;GET BYTE OF MSG
JUMPE T1,EOEND ;QUIT WHEN NULL
AOJA T2,EOLP ;INCR CHAR COUNT
EOEND: MOVEM T2,CHRCNT ;SAVE COUNT
MOVE T1,ERPTR ;GET ERROR POINTER
MOVEM T1,CHRPTR ;SAVE IT FOR PUTSTR
PUSHJ P,PUTSTR ;OUTPUT THE ERROR STRING DIRECTLY
PUSHJ P,%OCRLF ;END WITH CRLF, SUPPRESS NEXT LEADING ONE
MOVE T1,BYTN(D) ;UPDATE EOFN
SUB T1,OCNT(D)
MOVEM T1,EOFN(D)
MOVX T1,D%MOD ;Remember file modified
IORM T1,FLAGS(D)
POP P,U.ERR ;AND ORIGINAL ERROR UNIT #
POP P,D ;RESTORE U AND D
POP P,U
POPJ P,
ETTY: SKIPN T1,D.TTY ;ANY TTY DDB?
JRST EPSOUT ;NO. JUST GO OUTPUT MESSAGE
MOVE T0,FLAGS(T1) ;YES. GET FLAGS
TXNE T0,D%SEOL ;Suppress CRLF?
JRST EPSOUT ;YES. JUST GO OUTPUT MESSAGE
IF20,<
HRROI T1,%CRLF
PSOUT%
EPSOUT: MOVE T1,ERPTR ;GET POINTER TO MESSAGE
PSOUT%
HRROI T1,%CRLF ;END WITH CRLF
PSOUT%
> ;END IF20
IF10,<
OUTSTR %CRLF
EPSOUT: MOVE T1,ERPTR ;GET POINTER TO MESSAGE
OUTSTR (T1) ;TYPE MESSAGE
OUTSTR %CRLF ;END WITH CRLF
> ;END IF10
SKIPN T1,D.TTY ;AGAIN, ANY TTY DDB?
POPJ P, ;NO. DONE
MOVX T2,D%SEOL ;SUPPRESS NEXT LEADING CRLF
IORM T2,FLAGS(T1)
POPJ P, ;DONE
SEGMENT DATA
%CUNIT: BLOCK 1 ;CURRENT UNIT IN USE
ERPTR: BLOCK 1 ;ERROR MESSAGE POINTER
SEGMENT CODE
;OUTPUT CARRIAGE CONTROL
;IF CARRIAGE CONTROL IS BEING DONE, SUBSTITUTES FOR FIRST CHAR
;IF FIXED-LENGTH RECORDS, PADS OR TRUNCATES RECORD TO CORRECT LENGTH
;
;RETURN: ORPTR = BYTE POINTER TO FIRST CHAR OF RECORD
; ORLEN = NUMBER OF BYTES IN RECORD
FIXREC: SETZM G.PRP ;ASSUME NO PROMPTING
SKIPN RSIZE(D) ;FIXED-LENGTH RECORD?
JRST RECVAR ;NO
PUSHJ P,SFLEN ;UPDATE LENGTH, PAD
SKIPE FRSIZW(D) ;WORD-ALIGNED RECORDS?
PUSHJ P,FIXEOL ;HANDLE CRLF, CLEAR UNUSED PART OF LAST WORD
MOVE T1,FRSIZB(D) ;GET FULL RECORDSIZE
MOVEM T1,ORLEN(D) ;SAVE RECORD LENGTH
MOVEM T1,ORCNT(D) ;AND SAVE FOR OUTPUT ROUTINE
MOVE T1,ORBUF(D) ;SETUP PNTR/COUNT
MOVEM T1,ORPTR(D)
POPJ P,
RECVAR: LOAD T1,CC(U) ;GET CARRIAGE CONTROL DESIRED
CAIN T1,CC.FORT ;FORTRAN?
JRST CCFORT ;YES. OH, WELL
PUSHJ P,SVLEN ;SET PNTR/COUNT TO END OF RECORD
PUSHJ P,LISCOM ;GO HANDLE $ FORMAT, PROMPTING, CRLF
MOVE T1,ORBUF(D) ;SETUP PNTR/COUNT
MOVEM T1,ORPTR(D)
MOVE T1,ORLEN(D)
MOVEM T1,ORCNT(D)
POPJ P,
CCFORT: PUSHJ P,CHKDOL ;CHECK FOR $ CARRIAGE CONTROL
PUSHJ P,SVLEN ;UPDATE RECORD LENGTH
PUSHJ P,CCOUT ;OUTPUT CC CHARS
PUSHJ P,SETNUL ;AND END RECORD WITH NULLS
MOVE T1,ORBEG(D) ;GET POINTER TO RECORD
IBP T1 ;INCR TO FIRST DATA CHARACTER
MOVEM T1,G.PRP ;SAVE FOR PROMPT
MOVEM T1,ORPTR(D) ;AND FOR OUTPUT ROUTINE
MOVE T1,ORLEN(D) ;GET RECORD LENGTH
SUBI T1,1 ;REDUCE 1 FOR CC CHAR
MOVEM T1,ORCNT(D) ;SAVE FOR OUTPUT ROUTINE
POPJ P,
;ROUTINES CALLED BY FIXREC
SVLEN: SKIPN ORPOS(D) ;CHARS DEPOSITED HERE?
JRST SVOK ;YES. GO CHECK LENGTH
MOVE T1,FLAGS(D) ;NO. $ FORMAT?
TXNN T1,D%STCR
JRST ENDSET ;NO. SET POINTER/COUNT TO PREVIOUS LENGTH
SKIPL ORCNT(D) ;YES. BEYOND PHYSICAL RECORD?
JRST SVOK ;NO. JUST RESET LENGTH
MOVM T3,ORCNT(D) ;YES. EXPAND BUFFER
PUSHJ P,EXPORB
SVOK: MOVE T1,ORSIZ(D) ;CALCULATE CURRENT POSITION
SUB T1,ORCNT(D)
CAMGE T1,ORLEN(D) ;BEYOND OR AT PREVIOUSLY RECORDED LENGTH?
JRST ENDSET ;NO. GO SET PNTR/COUNT TO END OF RECORD
MOVEM T1,ORLEN(D) ;YES. RECORD NEW ONE
POPJ P,
SFLEN: SKIPN ORPOS(D) ;CHARS DEPOSITED HERE?
JRST SFOK ;YES. GO CHECK LENGTH
MOVE T1,FLAGS(D) ;NO. $ FORMAT?
TXNN T1,D%STCR
JRST ORPAD ;NO. PAD AT PREVIOUSLY RECORDED END
SKIPL ORCNT(D) ;BEYOND PHYSICAL RECORD END?
JRST SFOK ;NO. JUST CHECK LENGTH
MOVE T1,RSIZE(D) ;YES. SET TO FIXED RECORDSIZE
MOVEM T1,ORLEN(D)
PJRST %SOPOS
SFOK: MOVE T1,ORSIZ(D) ;CALCULATE CURRENT POSITION
SUB T1,ORCNT(D)
CAMGE T1,ORLEN(D) ;BEYOND OR AT PREVIOUSLY RECORDED LENGTH?
JRST ORPAD ;NO. GO PAD IT THERE
MOVEM T1,ORLEN(D) ;YES. SAVE NEW ONE
CAMN T1,RSIZE(D) ;RECORD FILLED ALREADY?
POPJ P, ;YES. NO NEED FOR PADDING!
ORPAD: MOVE T4,ORLEN(D) ;GET RECORDED LENGTH
MOVE T3,RSIZE(D) ;GET RECORD SIZE
MOVEM T3,ORLEN(D) ;SAVE AS UPDATED LENGTH
SUB T3,T4 ;GET AMOUNT OF PAD NEEDED
JUMPLE T3,ENDSET ;IF NONE, LEAVE
ADJBP T4,ORBEG(D) ;GET BYTE POINTER TO CURRENT LENGTH POINT
SETZB T0,T1 ;NO SOURCE
LOAD T2,PADCH(U) ;GET PAD CHAR
MOVEM T2,%MSPAD ;SAVE FOR MOVSLJ
EXTEND T0,%MSLJ ;PAD THE RECORD
$SNH
ENDSET: MOVE T1,ORLEN(D) ;GET LENGTH
ADJBP T1,ORBEG(D) ;GET POINTER TO END OF RECORD
MOVEM T1,ORPTR(D) ;SAVE IT
MOVE T1,ORSIZ(D) ;GET BUFFER LENGTH
SUB T1,ORLEN(D) ;GET # CHARS LEFT
MOVEM T1,ORCNT(D) ;SAVE IT
POPJ P,
;CHKDOL - CHECK IF $ CARRIAGE CONTROL, WHICH IS SPACE CARRIAGE CONTROL
;AND $ FORMAT, I.E., SUPPRESS THE NEXT CRLF.
CHKDOL: MOVE T2,ORBEG(D) ;GET POINTER TO RECORD
ILDB T3,T2 ;GET THE 1ST CHARACTER
MOVX T1,D%STCR ;GET DOLLAR FORMAT BIT
CAIN T3,"$" ;DOLLAR CARRIAGE CONTROL?
IORM T1,FLAGS(D) ;YES. PRETEND WE GOT DOLLAR FORMAT
POPJ P,
;CCOUT - TO GET CARRIAGE CONTROL CHARACTERS OUT BEFORE THE RECORD
;GOES OUT. FOR VARIABLE-LENGTH RECORDS, WE ONLY OUTPUT
;THE NUMBER OF CHARACTERS NECESSARY FOR THE CC CHARS.
CCOUT: MOVE T2,ORBEG(D) ;GET POINTER TO RECORD
ILDB T3,T2 ;GET THE 1ST CHARACTER
CAIG T3,"3" ;IF OUT OF RANGE, TREAT AS SPACE
CAIGE T3,"*"
MOVEI T3,"4" ;SPACE IS JUST BEYOND LEGAL TABLE
MOVE T4,CCPTR-"*"(T3) ;GET POINTER TO LAST BYTE OF CC WORD
MOVE T5,CCLEN-"*"(T3) ;GET # CHARS IN CC SUBSTITUTION
MOVE T1,FLAGS(D) ;GET FLAG REG
TXZN T1,D%SEOL ;SUPPRESS LEADING CRLF?
JRST DOCC ;NO. JUST PROCEED
MOVE T4,CCALTP-"*"(T3) ;YES. GET ALTERNATE POINTER
MOVE T5,CCALTL-"*"(T3) ;AND COUNT
DOCC: TXZE T1,D%STCR ;DOLLAR FORMAT OR CC?
TXO T1,D%SEOL ;YES. SET FOR SUPPRESSING CRLF NEXT TIME
MOVEM T1,FLAGS(D) ;SAVE UPDATED FLAGS
JUMPE T5,%POPJ ;NO OUTPUT IF NO CHARS
MOVEM T5,CHRCNT ;SAVE PNTR/COUNT
MOVEM T4,CHRPTR
PJRST PUTSTR ;OUTPUT THE STRING
;FIXEOL - FOR FIXED-LENGTH RECORDS,
;OUTPUTS CRLF, CLEARS THE UNUSED BITS IN
;THE LAST DATA WORD.
FIXEOL: PUSHJ P,LISCOM ;OUTPUT CRLF, DEAL WITH $ FORMAT
LDB T1,[POINT 6,ORPTR(D),5] ;GET # BITS TO RIGHT OF DATA
MOVE T1,RGTMSK(T1) ;GET MASK
HRRZ T2,ORPTR(D) ;GET LOCAL ADDR
ANDCAM T1,(T2) ;CLEAR BITS TO RIGHT OF DATA
POPJ P,
LISCOM: MOVE T1,FLAGS(D) ;SEE IF $ FORMAT
TXZN T1,D%STCR
JRST LISTCR ;NO. GO OUTPUT CRLF, ADD 2 TO LENGTH
TXZ T1,D%SEOL ;DON'T SUPPRESS LEADING CRLF ON INPUT
MOVEM T1,FLAGS(D) ;SAVE FLAGS WITHOUT IT
MOVE T1,ORBEG(D) ;GET RECORD POINTER
MOVEM T1,G.PRP ;SAVE FOR PROMPT
SETNUL: SETZ T1, ;APPEND 2 NULLS TO THE RECORD FOR PROMPTING
PUSHJ P,%OBYTE
PJRST %OBYTE
;LISTCR - FOR CC=LIST, OUTPUT A CRLF AT THE END OF THE RECORD.
LISTCR: TXO T1,D%SEOL ;SUPPRESS LEADING CRLF FOR INPUT
MOVEM T1,FLAGS(D)
MOVEI T1,15 ;OUTPUT CR/LF
PUSHJ P,%OBYTE
MOVEI T1,12
PUSHJ P,%OBYTE
MOVEI T1,2 ;INCREMENT LENGTH
ADDM T1,ORLEN(D)
POPJ P,
CCPTR: POINT 7,[BYTE(7)%CR,%DC3] ;* : CR,DC3
POINT 7,[BYTE(7)%CR] ;+ : CR
POINT 7,[BYTE(7)%CR,%DC1] ;, : CR,DC1
POINT 7,[BYTE(7)%CR,%LF,%LF,%LF] ;- : CR,LF,LF,LF
POINT 7,[BYTE(7)%CR,%DC2] ;. : CR,DC2
POINT 7,[BYTE(7)%CR,%DC4] ;/ : CR,DC4
POINT 7,[BYTE(7)%CR,%LF,%LF] ;0 : CR,LF,LF
POINT 7,[BYTE(7)%CR,%FF] ;1 : CR,FF
POINT 7,[BYTE(7)%CR,%DC0] ;2 : CR,DC0
POINT 7,[BYTE(7)%CR,%VT] ;3 : CR,VT
POINT 7,[BYTE(7)%CR,%LF] ;SPACE : CR,LF
CCLEN: 2 ;* : CR,DC3
1 ;+ : CR
2 ;, : CR,DC1
4 ;- : CR,LF,LF,LF
2 ;. : CR,DC2
2 ;/ : CR,DC4
3 ;0 : CR,LF,LF
2 ;1 : CR,FF
2 ;2 : CR,DC0
2 ;3 : CR,VT
2 ;SPACE : CR,LF
;THE FOLLOWING POINTERS AND COUNTS ARE USED IF DOLLAR FORMAT
;HAS BEEN SPECIFIED. THE CR AND ONE LF (IF ANY) IS REMOVED FROM
;EACH STRING.
CCALTP: POINT 7,[BYTE(7)%DC3] ;* : DC3
0 ;+ :
POINT 7,[BYTE(7)%DC1] ;, : DC1
POINT 7,[BYTE(7)%LF,%LF] ;- : LF,LF
POINT 7,[BYTE(7)%DC2] ;. : DC2
POINT 7,[BYTE(7)%DC4] ;/ : DC4
POINT 7,[BYTE(7)%LF] ;0 : LF
POINT 7,[BYTE(7)%FF] ;1 : FF
POINT 7,[BYTE(7)%DC0] ;2 : DC0
POINT 7,[BYTE(7)%VT] ;3 : VT
0 ;SPACE :
CCALTL: 1 ;* : DC3
0 ;+ :
1 ;, : DC1
2 ;- : LF,LF
1 ;. : DC2
1 ;/ : DC4
1 ;0 : LF
1 ;1 : FF
1 ;2 : DC0
1 ;3 : VT
0 ;SPACE : LF
;ROUTINE TO NORMALIZE CRLF POSITION, BY TYPING PENDING CRLF, IF ANY
;
;WHEN WRITING A FILE WITH CC=FORTRAN, THE CRLFS COME BEFORE THE
;RECORDS INSTEAD OF AFTER THEM. THE REST OF THE WORLD PUTS CRLFS
;AFTER THEIR RECORDS. THIS ROUTINE IS CALLED TO GET IN SYNC WITH THE
;OUTSIDE WORLD WHEN NECESSARY.
;
;CALLED:
; WHEN SWITCHING FROM OUTPUT TO INPUT ON TTY.
; WHEN CLOSING THE TTY.
; WHEN DIVERTING ERROR MESSAGES TO A FILE
%OCRLF: MOVX T0,D%SEOL ;Suppress next CRLF
IORM T0,FLAGS(D)
MOVEI T1,2 ;SET BYTE COUNT, PTR
MOVEM T1,CHRCNT
MOVE T1,[POINT 7,%CRLF] ;POINT TO CRLF
MOVEM T1,CHRPTR
SETZM G.PRP ;SET NO PROMPT STRING AVAILABLE
PJRST PUTSTR ;OUTPUT THE CRLF
IF10,<
TORECS:
>;END IF10
DORECS:
XORECS: PUSHJ P,COREC ;DO IT
PJRST ORINI ;AND INITIALIZE THE POINTER/COUNT
IF10,<
TOREC:
>;END IF10
DOREC:
XOREC:
COREC: PUSHJ P,FIXREC ;SETUP FOR OUTPUT
MOVX T0,D%MOD ;Set file modified
IORM T0,FLAGS(D)
SKIPE RSIZE(D) ;FIXED-LENGTH RECORDS?
JRST OUTBLT ;YES. BLT THE RECORD OUT
SKIPG ORCNT(D) ;ANYTHING IN RECORD?
POPJ P, ;NO. LEAVE
JRST COCONT ;SKIP BUFFER PNTR UPDATE
COUTLP: MOVEM T0,ORCNT(D) ;SAVE UPDATED REC COUNT
MOVEM T1,ORPTR(D) ;AND POINTER
MOVEM T4,OPTR(D) ;SAVE UPDATED BUFFER PNTR
COCONT: SKIPG OCNT(D) ;ANY ROOM IN WINDOW?
PUSHJ P,ONXTW ;NO ROOM, OUTPUT A BUFFERFUL
MOVE T0,ORCNT(D) ;GET RECORD PNTR/COUNT
MOVE T1,ORPTR(D)
MOVE T3,OCNT(D) ;GET WINDOW PNTR/COUNT
MOVE T4,OPTR(D)
CAIGE T0,(T3) ;SOURCE .GE. DEST?
MOVE T3,T0 ;NO. RESTRICT DEST TO PREVENT FILL
MOVNI T2,(T3) ;UPDATE COUNT NOW, AS MOVSLJ CLEARS IT
ADDM T2,OCNT(D)
EXTEND T0,[EXP MOVSLJ,0] ;MOVE RECORD
JRST COUTLP ;LOOP IF TRUNCATED
MOVEM T4,OPTR(D)
IF10,<
MOVE T0,FLAGS(D) ;Get DDB flags
TXNE T0,D%INT ;INTERACTIVE DEVICE?
PUSHJ P,OSBUF ;YES. OUTPUT BUFFER
>;END IF10
MOVE T1,BYTN(D) ;GET BYTE # OF NEXT WINDOW
SUB T1,OCNT(D) ;GET LAST BYTE IN USE
MOVE T0,FLAGS(D) ;Get DDB flags
TXNE T0,D%RAN ;RANDOM FILE?
CAMLE T1,EOFN(D) ;YES. ONLY STORE LARGER EOFN
MOVEM T1,EOFN(D) ;SAVE AS EOF PNTR
POPJ P, ;DONE
OUTBLT: MOVE T1,FRSIZW(D) ;GET RECORDSIZE
MOVEM T1,LOCSIZ ;SAVE FOR TRANSFER
MOVE T1,ORBUF(D) ;INIT RECORD POINTER
MOVEM T1,ORPTR(D)
OUTBLP: MOVE T4,OCNT(D) ;GET BUFFER COUNT
IDIV T4,BPW(D) ;GET # WORDS LEFT
JUMPG T4,OUTBOK ;OK IF SOME
PUSHJ P,ONXTW ;GET MORE IF NONE
MOVE T4,OCNT(D) ;GET NEW COUNT
IDIV T4,BPW(D) ;IN WORDS
OUTBOK: MOVE T3,LOCSIZ ;GET # WORDS TO TRANSFER
CAILE T3,(T4) ;.GT. NUMBER OF WORDS IN BUFFER
MOVEI T3,(T4) ;YES. USE THE SMALLER ONE
HRRZ T5,OPTR(D) ;GET OUTPUT BUFFER ADDR-1
ADDI T5,1 ;CORRECT IT
HRRZ T1,ORPTR(D) ;GET RECORD ADDR-1
HRLZI T1,1(T1) ;GET ITS ADDRESS AS SOURCE
HRRI T1,(T5) ;DESTINATION IS OUTPUT BUFFER
ADDI T5,-1(T3) ;GET FINAL DEST
BLT T1,(T5) ;TRANSFER THE WORDS
ADDM T3,ORPTR(D) ;UPDATE RECORD PNTR
ADDM T3,OPTR(D) ;AND BUFFER POINTER
SUBI T4,(T3) ;AND BUFFER WORD COUNT
IMUL T4,BPW(D) ;UPDATE COUNT
MOVEM T4,OCNT(D)
MOVNI T3,(T3) ;GET NEG # WORDS TRANSFERRED
ADDB T3,LOCSIZ ;UPDATE TOTAL NUMBER
JUMPG T3,OUTBLP ;IF MORE, TRY FOR MORE
MOVE T1,BYTN(D) ;GET BYTE # OF NEXT WINDOW
SUB T1,OCNT(D) ;GET LAST BYTE IN USE
MOVE T0,FLAGS(D) ;Get DDB flags
TXNE T0,D%RAN ;RANDOM FILE?
CAMLE T1,EOFN(D) ;YES. ONLY STORE LARGER EOFN
MOVEM T1,EOFN(D) ;SAVE AS EOF PNTR
POPJ P,
IF10,<
TOSTR: PUSHJ P,DOSTR ;PUT THE CHARS IN THE BUFFER
PJRST OSBUF ;GO OUTPUT BUFFER
> ;END IF10
DOSTR:
DSTRLP: SKIPG OCNT(D) ;ANY ROOM LEFT IN BUFFER?
PUSHJ P,ONXTW ;NO. GET NEW WINDOW
SOS OCNT(D) ;DECR COUNT
ILDB T1,CHRPTR ;GET A CHAR
IDPB T1,OPTR(D) ;DEPOSIT IN FILE BUFFER
SOSLE CHRCNT ;DECR COUNT
JRST DSTRLP ;BACK FOR MORE
POPJ P,
IF20,<
;TOPS-20 TTY OUTPUT
TORECS: PUSHJ P,TOREC ;OUTPUT THE RECORD
PJRST ORINI ;GO INIT THE POINTER/COUNT
TOREC: PUSHJ P,FIXREC ;SETUP FOR OUTPUT
SKIPG ORCNT(D) ;ANY DATA IN RECORD?
POPJ P, ;NO. NOTHING TO DO
LOAD T1,OJFN(D) ;GET JFN
RFCOC% ;SAVE CCOC WORDS FOR USE DURING TEXTI
DMOVEM T2,TCCOC ;SAVE TEMPORARILY
AND T2,%CCMSK ;SET CCOC FOR CORRECT OUTPUT
IOR T2,%OCCOC ;LEAVE ^I AND ^L AS THEY WERE, SET OTHERS
MOVE T3,%OCCOC+1 ; TO SEND LITERALLY
SFCOC%
LOAD T1,OJFN(D) ;GET JFN
MOVE T2,ORPTR(D) ;GET POINTER TO START OF RECORD
MOVN T3,ORCNT(D) ;GET NEGATIVE OF BYTE COUNT
LOAD T1,OJFN(D) ;GET JFN
SOUTR% ;OUTPUT THE STRING
ERJMP OUTERR ;ERROR, GO TELL USER
LOAD T1,OJFN(D) ;GET JFN AGAIN
DMOVE T2,TCCOC ;GET ORIGINAL CONTENTS
SFCOC% ;RESTORE CCOC WORDS
POPJ P, ;DONE
TOSTR: LOAD T1,OJFN(D) ;GET JFN
RFCOC% ;SAVE CCOC WORDS FOR USE DURING TEXTI
DMOVEM T2,TCCOC ;SAVE TEMPORARILY
AND T2,%CCMSK ;SET CCOC FOR CORRECT OUTPUT
IOR T2,%OCCOC ;LEAVE ^I AND ^L AS THEY WERE, SET OTHERS
MOVE T3,%OCCOC+1 ; TO SEND LITERALLY
SFCOC%
LOAD T1,OJFN(D) ;GET JFN
MOVE T2,CHRPTR ;GET POINTER
MOVN T3,CHRCNT ;AND COUNT
SOUTR% ;OUTPUT THE STRING
ERJMP OUTERR ;ERROR, GO TELL USER
LOAD T1,OJFN(D) ;GET JFN AGAIN
DMOVE T2,TCCOC ;GET ORIGINAL CONTENTS
SFCOC% ;RESTORE CCOC WORDS
POPJ P,
>;END IF20
;ENCODE
ENCINI: MOVE T1,A.HSA ;GET STRING ADDR
$BLDBP T1 ;Build 7-bit byte ptr.
MOVE T2,T.HSA ;GET ARRAY TYPE
CAIN T2,TP%CHR ;CHARACTER?
MOVE T1,@A.HSA ;YES. GET THE POINTER
MOVEM T1,ORPTR(D)
MOVEM T1,ORBUF(D)
MOVEM T1,ORBEG(D)
SKIPG T1,@A.HSL ;GET STRING LENGTH
$ECALL SLN,%ABORT ;RECORD LENGTH NOT POSITIVE
MOVEM T1,ORCNT(D)
MOVEM T1,RSIZE(D) ;AND RECORD SIZE
MOVEM T1,ORBLN(D) ;AND REC BUFFER LENGTH
MOVEM T1,ORSIZ(D)
MOVEM T1,BYTN(D) ;SET NEXT RECORD START
MOVEM T1,ORLEN(D) ;AND RECORD LENGTH
PJRST EFILL ;GO FILL WITH BLANKS
ENCODE: MOVE T1,BYTN(D) ;GET NEXT RECORD START
ADJBP T1,ORBUF(D) ;MOVE THE POINTER
MOVEM T1,ORBEG(D) ;SAVE PNTR TO BEG OF RECORD
MOVEM T1,ORPTR(D) ;AND MOVING POINTER
MOVE T1,ORSIZ(D) ;GET RECORD LENGTH
MOVEM T1,ORCNT(D) ;SAVE IN MOVING LENGTH
ADDM T1,BYTN(D) ;UPDATE NEXT RECORD START
PJRST EFILL ;GO FILL WITH BLANKS
;INTERNAL FILE OUTPUT INITIALIZATION. SIMILAR TO INPUT.
;SETUP THE POINTER/COUNT TO THE BEGINNING OF THE CHARACTER
;VARIABLE OR ARRAY.
IFOINI: MOVE T1,A.UNIT ;GET DESCRIPTOR ADDRESS
MOVE T2,(T1) ;GET BYTE POINTER
MOVEM T2,ORBUF(D) ;SAVE AS BASE POINTER
MOVEM T2,ORBEG(D)
MOVEM T2,ORPTR(D) ;AND MOVING POINTER
MOVE T2,1(T1) ;GET SIZE
MOVEM T2,ORBLN(D) ;SAVE AS BUFFER SIZE
MOVEM T2,ORSIZ(D)
MOVEM T2,ORCNT(D) ;AND MOVING SIZE
MOVEM T2,ORLEN(D) ;AND RECORD LENGTH
MOVEM T2,RSIZE(D) ;AND RECORD SIZE
MOVEM T2,BYTN(D) ;SET NEXT RECORD START
MOVE T3,@A.HSL ;GET TOTAL # CHARS IN ARRAY
SKIPN A.HSL ;UNLESS THERE IS NO KEYWORD
MOVE T3,1(T1) ;NONE. GET IT FROM THE DESCRIPTOR
MOVEM T3,EOFN(D) ;SAVE TO PREVENT OVERRUN
JUMPG T3,EFILL ;GO SPACE-FILL IF NON-ZERO
$ECALL ICE,%ABORT ;ILLEGAL CHARACTER EXPRESSION
;INTERNAL FILE OUTPUT - MOVES THE POINTERS AND RESETS THE COUNT
;ONLY CALLED BY FORMATS WITH "/" OR INDEFINITE REPEAT.
;FILLS THE NEXT RECORD WITH SPACES.
;IF THE NEW RECORD IS BEYOND THE BOUNDS OF THE VARIABLE
;OR ARRAY, REPORT A FATAL ERROR.
IFOUT: MOVE T1,BYTN(D) ;GET NEXT RECORD START
CAML T1,EOFN(D) ;PAST END OF ARRAY?
$ECALL WBA,%ABORT ;YES. WRITING BEYOND END OF ARRAY
ADJBP T1,ORBUF(D) ;MOVE THE POINTER
MOVEM T1,ORBEG(D) ;SAVE POINTER TO BEG OF RECORD
MOVEM T1,ORPTR(D) ;AND MOVING POINTER
MOVE T1,ORSIZ(D) ;GET RECORD LENGTH
MOVEM T1,ORCNT(D) ;SAVE IN MOVING LENGTH
ADDM T1,BYTN(D) ;UPDATE NEXT RECORD START
EFILL: DMOVE T0,[EXP 1,<POINT 7,[ASCIZ / /]>] ;USE SPACES
MOVE T3,ORSIZ(D) ;GET LENGTH OF ENTRY
MOVE T4,ORPTR(D) ;AND POINTER
EXTEND T0,[EXP MOVSLJ," "];FILL WITH BLANKS
$SNH ;SHOULD SKIP RETURN ALWAYS
POPJ P,
SUBTTL T FORMAT
;ROUTINE TO READ RECORD POSITION
;RETURN: T1 = BYTE NUMBER OF NEXT BYTE TO/FROM RECORD
; I.E., NUMBER OF BYTES ALREADY READ FROM RECORD OR STORED IN IT
;PRESERVES T2-T5
%RIPOS: MOVE T1,IRLEN(D) ;GET RECORD LENGTH
SUB T1,IRCNT(D) ;SUBTRACT # CHARS LEFT IN IT
ADDI T1,1 ;BEG OF RECORD IS COL 1
POPJ P,
%ROPOS: MOVE T1,ORSIZ(D) ;GET RECORD BUFFER LENGTH
SUB T1,ORCNT(D) ;SUBTRACT EMPTY SPACE
ADDI T1,1 ;BEG OF RECORD IS COL 1
POPJ P, ;RETURN WITH BYTE NUMBER
;ROUTINE TO SET RECORD POSITION
;ARG: T1 = BYTE NUMBER
;SETS SO THAT NEXT IBYTE/OBYTE CALL GETS OR STORES THE GIVEN BYTE
%CIPOS: MOVE T2,IRLEN(D) ;GET BUFFER SIZE
SUB T2,IRCNT(D) ;CALC CURRENT POSITION
ADD T1,T2 ;CALC DESIRED POSITION
JUMPGE T1,SIPOK ;OK IF POS OR ZERO
SETZ T1, ;ELSE SET IT TO ZERO
JRST SIPOK
%SIPOS: SOJGE T1,SIPOK ;OK IF POSITIVE, DECR TO 1 BEFORE IT
SETZ T1, ;ELSE USE ZERO
SIPOK: MOVE T2,IRLEN(D) ;GET BUFFER SIZE
SUB T2,T1 ;CALC # CHARS LEFT IN RECORD
MOVEM T2,IRCNT(D) ;SAVE IT
ADJBP T1,IRBEG(D) ;FIX POINTER
MOVEM T1,IRPTR(D) ;SAVE IT
POPJ P,
%COPOS: MOVE T2,ORSIZ(D) ;CALC CURRENT POSITION
SUB T2,ORCNT(D)
ADD T1,T2 ;CALC DESIRED DESTINATION
JUMPGE T1,CHKPOS ;OK IF POS OR ZERO
SETZ T1, ;MAKE IT ZERO IF NOT
JRST CHKPOS
%SOPOS: SOJGE T1,SOPOK ;OK IF POS, DECR TO 1 BEFORE IT
SETZ T1, ;ELSE USE BEG OF RECORD
SOPOK: MOVE T2,ORSIZ(D) ;GET BUFFER SIZE
SUB T2,ORCNT(D) ;GET CURRENT POSITION
CHKPOS: SKIPE ORPOS(D) ;CHARS DEPOSITED HERE?
JRST NOULEN ;NO. DON'T UPDATE RECORDED LENGTH
CAMLE T2,ORLEN(D) ;YES. BEYOND LAST RECORDED LENGTH?
MOVEM T2,ORLEN(D) ;YES. SAVE NEW ONE
NOULEN: SETOM ORPOS(D) ;FLAG CHARS NOT DEPOSITED HERE
MOVE T2,ORSIZ(D) ;GET DATA BUFFER SIZE
SUBI T2,(T1) ;CALC COUNT OF CHARS LEFT
MOVEM T2,ORCNT(D) ;AND SAVE IT
ADJBP T1,ORBEG(D) ;FIX POINTER
MOVEM T1,ORPTR(D) ;SAVE IT
POPJ P,
SEGMENT DATA
TCCOC: BLOCK 2 ;CURRENT CCOC WORDS
CHRPTR: BLOCK 1 ;STRING BYTE POINTER
CHRCNT: BLOCK 1 ;COUNT
SEGMENT CODE
SUBTTL UNFORMATTED I/O
UISET: AOS CREC(D) ;UPDATE RECORD COUNT
PUSHJ P,ILSCW1 ;READ START LSCW
$ECALL EOF,%ABORT ;EOF.
SETZM RECREM ;CLEAR CHAR REMAINDER
POPJ P,
UNFI: SKIPN IO.ADR ;FIN CALL?
JRST UIEND ;YES
MOVE T1,IO.TYP ;GET TYPE
CAIN T1,TP%CHR ;CHARACTER?
JRST UICHR ;YES. GO DO IT
SETZM RECREM ;CLEAR CHAR REMAINDER
MOVE T1,IO.SIZ ;GET DATA SIZE
CAME T1,IO.INC ;IS IT THE SIMPLE CASE?
JRST UIWRD ;NO. MUST BE DONE WORD BY WORD
IMUL T1,IO.NUM ;CALC # WORDS
MOVEM T1,IO.SIZ ;SAVE AS DATA SIZE
MOVEI T1,1 ;SET DATA COUNT TO 1
MOVEM T1,IO.NUM
SETZM IO.INC ;WITH NO INCREMENT
JRST UIBLP ;GO DO THE BLT
UIWRD: MOVN T1,IO.SIZ ;ACCOUNT FOR THE INCREMENT
ADDM T1,IO.INC ;DONE FOR EACH ENTRY AUTOMATICALLY
UIBLP: MOVE T1,IO.SIZ ;GET DATA SIZE
MOVEM T1,LOCSIZ ;SET LOCAL SIZE
UIBLP1: SKIPLE RECLEN ;ANY WORDS LEFT IN SEGMENT?
JRST UIWIN ;YES. GO DO BLT
PUSHJ P,ILSCWX ;NO. READ A NEW SEGMENT
JUMPLE T1,UIZERO ;NO DATA LEFT IF .LE. ZERO
UIWIN: DMOVE P1,IPTR(D) ;GET PNTR/COUNT
IDIV P2,BPW(D) ;GET # WORDS LEFT
JUMPG P2,UIBLT ;IF DATA LEFT IN WINDOW, CONTINUE WITH IT
PUSHJ P,UINXTW ;READ NEXT WINDOW
$ECALL EOF,%ABORT ;REPORT EOF IMMEDIATELY
DMOVE P1,IPTR(D) ;GET PNTR/COUNT AGAIN
IDIV P2,BPW(D) ;GET # WORDS LEFT
UIBLT: MOVE T2,LOCSIZ ;GET MIN OF ARRAY LENGTH
CAILE T2,(P2) ; AND WINDOW LENGTH
MOVEI T2,(P2)
CAMLE T2,RECLEN ; AND RECORD LENGTH
MOVE T2,RECLEN
;IO.ADR/ Address of data
;P1/ local FOROTS address of data
;T2/ number of words to copy
MOVE T1,IO.ADR ;GET USER'S ARRAY ADDR
TLNN T1,-1 ;Extended addressing?
JRST UIBLT1 ;No, normal BLT
MOVE T3,T2 ;COPY # WORDS TO BLT
MOVEI T4,(P1) ;GET LOCAL ADDR
XMOVEI T4,1(T4) ;T4/ "From" -- get FOROTS address of data
MOVE T5,IO.ADR ;T5/ "To"-- user's array.
EXTEND T3,[XBLT] ;** Copy the data **
JRST UIBLT2 ;Skip normal BLT
UIBLT1: MOVE T1,IO.ADR ;GET ARRAY ADDRESS
MOVSI T4,1(P1) ;GET BLT-FROM ADDRESS
HRRI T4,(T1) ;AND BLT-TO ADDRESS
ADDI T1,(T2) ;POINT TO END+1 OF BLT
BLT T4,-1(T1) ;MOVE DATA INTO ARRAY
UIBLT2: ADDI P1,(T2) ;INCREMENT ADDRESS OF DATA IN WINDOW
HXL P1,BYTPT(D) ;WORD-ALIGN IT
SUBI P2,(T2) ;DECREMENT COUNT OF DATA LEFT IN WINDOW
IMUL P2,BPW(D) ;GET # CHARS
DMOVEM P1,IPTR(D) ;SAVE THEM BOTH
ADDM T2,IO.ADR ;INCR DATA ADDR
MOVNI T2,(T2) ;GET NEG # WORDS TRANSFERRED
ADDM T2,RECLEN ;AND RECORD LENGTH
ADDB T2,LOCSIZ ;AND NUMBER OF WORDS OF DATA
JUMPG T2,UIBLP1 ;IF SOME LEFT, CONTINUE
MOVE T1,IO.INC ;GET INCREMENT
ADDM T1,IO.ADR ;ADD TO DATA ADDRESS
SOSLE T1,IO.NUM ;DECR COUNT
JRST UIBLP ;MORE TO DO
POPJ P, ;ELSE RETURN
UIZLP: MOVE T1,IO.SIZ ;GET DATA SIZE
MOVEM T1,LOCSIZ ;SAVE IT LOCALLY
UIZERO: MOVE T1,IO.ADR ;GET DATA ADDRESS
SETZM (T1) ;CLEAR FIRST WORD
MOVE T2,LOCSIZ ;GET # WORDS TO CLEAR
CAIG T2,1 ;MORE THAN 1 WORD?
POPJ P, ;NO. DONE
TLNN T1,-1 ;Extended addressing?
JRST UZSKP1 ;No, normal BLT
MOVE T3,T2 ;T2/ # words to copy
SUBI T3,1 ;ALREADY CLEARED ONE
MOVE T4,T1 ;t3/ "from" the array
XMOVEI T5,1(T1) ;T4/ "to" array+1
EXTEND T3,[XBLT] ;** Zero array **
JRST UIZINC ;DONE WITH THIS BATCH
UZSKP1: MOVSI T4,(T1) ;SET BLT-FROM ADDRESS
HRRI T4,1(T1) ;AND BLT-TO ADDRESS
ADDI T1,(T2) ;POINT TO END+1 OF BLT
BLT T4,-1(T1) ;CLEAR WHOLE ARRAY
UIZINC: MOVE T1,IO.INC ;GET INCREMENT
ADDM T1,IO.ADR ;INCR DATA ADDR
SOSLE IO.NUM ;DECR DATA COUNT
JRST UIZLP ;MORE TO DO
POPJ P, ;DONE
UICHR: MOVE T1,RECLEN ;GET # WORDS LEFT IN RECORD
IMUL T1,BPW(D) ;GET # CHARS
ADD T1,RECREM ;ADD PREVIOUS REMAINDER
MOVEM T1,LOCREC ;SAVE LOCAL RECORD LENGTH
MOVE T1,IO.SIZ ;GET SIZE
CAME T1,IO.INC ;SIMPLE CASE?
JRST UICHR1 ;NO. DO IT CHAR BY CHAR
IMUL T1,IO.NUM ;GET TOTAL # CHARS
MOVEM T1,IO.SIZ ;MAKE IT LOOK LIKE 1 BIG VARIABLE
MOVEI T1,1 ;DATA COUNT OF 1
MOVEM T1,IO.NUM
SETZM IO.INC ;NO INCREMENT NECESSARY
JRST UICBLP ;GO DO THE BLT
UICHR1: MOVN T1,IO.SIZ ;ACCOUNT FOR THE INCREMENT DONE
ADDM T1,IO.INC ;DONE FOR EACH ENTRY AUTOMATICALLY
UICBLP: MOVE T1,IO.SIZ ;GET ENTRY SIZE
MOVEM T1,LOCSIZ ;SET UP LOCAL ONE
UICBL1: SKIPLE LOCREC ;ANY DATA LEFT IN SEGMENT?
JRST UICWIN ;YES. GO TRANSFER A CHAR
PUSHJ P,ILSCWX ;NO. GET A NEW SEGMENT
JUMPLE T1,UICBZ ;NO NEW DATA FOUND IF .LE. ZERO
IMUL T1,BPW(D) ;GET # CHARS
MOVEM T1,LOCREC ;SAVE IT
UICWIN: SKIPLE ICNT(D) ;ANY CHARS IN WINDOW
JRST UICBLT ;YES. GO TRANSFER SOME
PUSHJ P,UINXTW ;NO. GET A NEW WINDOW
$ECALL EOF,%ABORT ;EOF. REPORT IT IMMEDIATELY
UICBLT: MOVE T0,ICNT(D) ;GET MINIMUM OF WINDOW COUNT
CAMLE T0,LOCREC ;AND CHARS IN RECORD
MOVE T0,LOCREC
CAMLE T0,LOCSIZ ;AND NUMBER OF CHARS TO TRANSFER
MOVE T0,LOCSIZ
MOVEM T0,LOCNUM ;SAVE IT
MOVE T1,IPTR(D) ;GET THE INPUT PNTR
MOVE T3,T0 ;COPY THE COUNT
MOVE T4,IO.ADR ;GET DEST PNTR
EXTEND T0,[EXP MOVSLJ,0] ;MOVE STRING LEFT-JUSTIFIED, ZERO FILL
$SNH ;SHOULD SKIP RETURN
MOVEM T1,IPTR(D) ;SAVE UPDATED BUFFER PNTR
MOVE T4,LOCNUM ;GET # CHARS TRANSFERRED
ADJBP T4,IO.ADR ;ADJUST - UPDATED PNTR IS 2-WORD!
MOVEM T4,IO.ADR ;SAVE IT
MOVN T1,LOCNUM ;GET NEGATIVE CHARS TRANSFERRED
ADDM T1,LOCREC ;UPDATE # CHARS LEFT IN RECORD
ADDM T1,ICNT(D) ;UPDATE # CHARS LEFT IN WINDOW
ADDB T1,LOCSIZ ;UPDATE TOTAL # CHARS TO TRANSFER
JUMPG T1,UICBL1 ;LOOP IF MORE TO TRANSFER
SKIPN T1,IO.INC ;GET INCREMENT
JRST UICNI ;NONE
ADJBP T1,IO.ADR ;UPDATE PNTR
MOVEM T1,IO.ADR ;AND SAVE IT
UICNI: SOSLE IO.NUM ;ANY MORE ENTRIES?
JRST UICBLP ;YES. GO DO THEM
MOVE T1,LOCREC ;GET LOCAL RECORD LENGTH LEFT
IDIV T1,BPW(D) ;GET WORDS AND BYTES
DMOVEM T1,RECLEN ;SAVE FOR NEXT CALL
POPJ P, ;NO. DONE WITH IOLST CALL
UICBZL: MOVE T1,IO.SIZ ;GET ENTRY SIZE
MOVEM T1,LOCSIZ ;SAVE LOCALLY
UICBZ: DMOVE T0,[EXP 1,<POINT 7,[ASCIZ / /]>] ;USE SPACES
MOVE T3,LOCSIZ ;DESTINATION # CHARS
MOVE T4,IO.ADR ;DEST PNTR
EXTEND [EXP MOVSLJ," "] ;FILL WITH SPACES
$SNH ;SHOULD SKIP RETURN
SKIPN T1,IO.INC ;GET INCREMENT
JRST UICZNI ;NONE
ADJBP T1,IO.ADR ;UPDATE THE PNTR
MOVEM T1,IO.ADR ;SAVE IT BACK
UICZNI: SOSLE IO.NUM ;ANY MORE ENTRIES?
JRST UICBZL ;YES. GO FILL THEM
SETZM RECLEN ;CLEAR THE RECORD LENGTH
SETZM RECREM ;AND THE BYTE REMAINDER
POPJ P,
UIEND: PUSHJ P,ILSCW3 ;SKIP TO END LSCW
MOVE T0,FLAGS(D) ;Get DDB flags
TXNN T0,D%END ;REACH EOF?
PJRST %SETAV ;NO. RETURN TO USER PROG
LOAD T0,MODE(D) ;GET DATA MODE
CAIE T0,MD.IMG ;BINARY?
$ECALL BBF,%ABORT ;YES. BAD FORMAT
$ECALL EOF,%ABORT ;NO. JUST EOF
UINXTW: PUSHJ P,INXTW ;MAP NEXT WINDOW
MOVE T0,FLAGS(D)
TXNN T0,D%END ;SEQUENTIAL FILE AND EOF?
AOS (P) ;NO. SKIP RETURN
POPJ P, ;YES. JUST RETURN NON-SKIP
;HERE AT START OF RECORD
;READ START LSCW
;0 MEANS RANDOM RECORD WAS NEVER WRITTEN
ILSCW1: LOAD T0,MODE(D) ;GET DATA MODE
CAIN T0,MD.IMG ;BINARY?
JRST IMG1 ;NO, IMAGE, NO LSCWS
PUSHJ P,IWORD ;GET WORD FROM BINARY FILE
POPJ P, ;EOF. NON-SKIP RETURN
JUMPE T1,RNRERR ;ZERO, RECORD WASN'T WRITTEN
LDB T2,[POINT 9,T1,8] ;GET SEGMENT CONTROL WORD
CAIE T2,1 ;START LSCW?
; IOERR (BBF,25,302,?,Bad format binary file,,%ABORT)
$ECALL BBF,%ABORT ;?Bad format binary file
TLZ T1,777000 ;GET SEGMENT LENGTH
SUBI T1,1 ;REMOVE LSCW FROM COUNT
SKIPN T2,RSIZE(D) ;RECORD SIZE SPECIFIED?
JRST SLSCW1 ;NO
CAIE T2,(T1) ;EQUAL TO SIZE FOUND?
$ECALL RSM,%ABORT ;NO. RECORD SIZE MISMATCH
SLSCW1: MOVEM T1,RECLEN ;SAVE COUNT
JRST %POPJ1 ;RETURN
IF20,<
PGERR: HLRZ T1,T2 ;[3247] GET PROCESS HANDLE
GETER% ;[3247]
HRRZ T1,T2 ;[3247] GET ERROR NUMBER
CAIE T1,LNGFX1 ;[3247] PAGE TABLE ERROR?
$ECALL IJE,%ABORT ;[3247] NO
> ;END IF20
RNRERR: $ECALL RNR,%ABORT ;RECORD NOT WRITTEN
IMG1: SKIPN T1,RSIZE(D) ;GET RECORD SIZE IN WORDS
HRLOI T1,37777 ;HUGE RECORD IF NO RECSIZ
MOVEM T1,RECLEN ;SAVE IT
JRST %POPJ1 ;DONE
;HERE WHEN START OR CONTINUE SEGMENT ENDS
;MUST SEE CONTINUATION OR END LSCW
ILSCWX: LOAD T0,MODE(D) ;GET DATA MODE
CAIN T0,MD.IMG ;BINARY MODE?
JRST IMG2 ;NO, IMAGE, FAKE A CONTINUATION LSCW
SKIPGE T1,RECLEN ;IF SEG LEN NEG, THEN LCSW 3
POPJ P, ;AREADY SEEN. RETURN NEGATIVE
PUSHJ P,IWORD ;GET WORD FROM BINARY FILE
$ECALL BBF,%ABORT ;EOF: ?"Bad format binary file"
SETO T3, ;ASSUME 0 SEGMENT LENGTH
LDB T2,[POINT 9,T1,8] ;GET SEGMENT CONTROL WORD
CAIN T2,3 ;END LSCW?
JRST ILXEND ;YES. END OF LOGICAL RECORD
CAIE T2,2 ;CONTINUATION LSCW?
$ECALL BBF,%ABORT ;NO. BAD LSCW, BAD BINARY FILE
MOVE T3,T1 ;GET THE LSCW
TLZ T3,777000 ;GET THE SEGMENT LENGTH
SUBI T3,1 ;REMOVE LSCW FROM COUNT
SKIPE RSIZE(D) ;ANY RECORDSIZE SPECIFIED?
$ECALL FCL,%ABORT ;FOUND UNEXPECTED CONTINUATION LSCW
ILXEND: MOVE T1,T3 ;RETURN LENGTH IN T1
MOVEM T1,RECLEN ;STORE SEGMENT LENGTH
POPJ P,
IMG2: SETZ T1, ;NO RECORD LENGTH LEFT
MOVEM T1,RECLEN
POPJ P,
;HERE AT END OF IO LIST
;POSITION FILE JUST AFTER END LSCW
;NUMBER OF WORDS TO DISCARD IS .GE. 0 IN RECLEN
ILSCW3: LOAD T0,MODE(D) ;GET DATA MODE
CAIN T0,MD.IMG ;BINARY?
JRST IMG3 ;NO, NO LSCW
PUSHJ P,UIALIN ;WORD-ALIGN THE PNTR/COUNT
SKIPGE P3,RECLEN ;GET SEGMENT LENGTH LEFT
POPJ P, ;IF NEG, ALREADY READ LSCW 3
ILS3LP: PUSHJ P,IAWORD ;GET WORD FROM BINARY FILE
$ECALL BBF,%ABORT ;EOF. FILE IN ERROR
SOJGE P3,ILS3LP ;SKIP TILL LSCW
LDB T2,[POINT 9,T1,8] ;GET SEGMENT CONTROL WORD
CAIE T2,2 ;CONTINUE LSCW?
JRST NLSCW2 ;NO
MOVE P3,T1 ;COPY THE LSCW
TLZ P3,777000 ;GET THE SEGMENT LENGTH
SOJA P3,ILS3LP ;CONTINUE
NLSCW2: CAIE T2,3 ;END LSCW?
$ECALL BBF,%ABORT ;No, file in error.
POPJ P, ;DONE
IMG3: SKIPN RSIZE(D) ;RECORD SIZE SPECIFIED?
POPJ P, ;NO - WE HAVE NO CLEANUP
PUSHJ P,UIALIN ;WORD-ALIGN THE PNTR/COUNT
SKIPG P4,RECLEN ;GET RECORD LENGTH LEFT
POPJ P, ;NONE LEFT - WE'RE DONE
IMG3LP: PUSHJ P,IAWORD ;READ A WORD
SETZ P4, ;EOF, OK
SOJG P4,IMG3LP ;LOOP BACK
POPJ P, ;RETURN
UIALIN: DMOVE T1,IPTR(D) ;GET PNTR/COUNT
HXL T1,BYTPT(D) ;ALIGN THE PNTR
IDIV T2,BPW(D) ;ALIGN THE COUNT
IMUL T2,BPW(D)
DMOVEM T1,IPTR(D)
POPJ P,
IANXT: PUSHJ P,UINXTW ;NOTHING LEFT, GO MAP NEXT WINDOW
POPJ P, ;EOF. NON-SKIP RETURN
IAWORD: SKIPG ICNT(D) ;ANY WORDS LEFT?
JRST IANXT ;NO
MOVN T1,BPW(D) ;REDUCE BY BYTES
ADDM T1,ICNT(D)
AOS T1,IPTR(D) ;INCR PNTR BY A WORD
MOVEI T1,(T1) ;GET JUST ADDR
MOVE T1,(T1) ;GET THE DATA
AOS (P) ;SKIP RETURN
POPJ P,
INXT: PUSHJ P,UINXTW ;NOTHING LEFT, GO MAP NEXT WINDOW
POPJ P, ;EOF. NON-SKIP RETURN
IWORD: MOVE P2,ICNT(D) ;GET THE COUNT
IDIV P2,BPW(D) ;ALIGN THE COUNT
SOJL P2,INXT ;CHECK IF WORD LEFT, DO INPUT IF NOT
HRRZ P1,IPTR(D) ;GET JUST THE RH OF THE PNTR
ADDI P1,1 ;INCREMENT POINTER
MOVE T1,(P1) ;GET WORD
HXL P1,BYTPT(D) ;MAKE IT A CHARACTER BYTE PNTR AGAIN
IMUL P2,BPW(D) ;AND MAKE THE COUNT IN BYTES
DMOVEM P1,IPTR(D) ;SAVE THEM BOTH
AOS (P) ;SKIP RETURN
POPJ P,
;UNFORMATTED SKIP RECORD
UNFSKP: AOS CREC(D) ;UPDATE RECORD COUNT
PUSHJ P,ILSCW1 ;READ START LSCW, P3 = SEGMENT LENGTH
$ECALL EOF,%ABORT ;EOF
JRST UIEND ;GO SKIP TO END OF RECORD
UOSET: MOVX T0,D%MOD ;Set "file modified"
IORM T0,FLAGS(D)
AOS CREC(D) ;UPDATE RECORD COUNT
LOAD T0,MODE(D) ;GET DATA MODE
CAIE T0,MD.IMG ;BINARY?
PUSHJ P,OLSCW1 ;YES. OUTPUT START LSCW
SKIPN T1,RSIZE(D) ;RECORD SIZE SPECIFIED?
HRLOI T1,37777 ;NO, SET BIG RECORDS
MOVEM T1,RECLEN ;SAVE IT FOR IOLST CALLS
SETZM RECREM ;CLEAR CHARACTER REMAINDER
POPJ P,
UNFO: SKIPN IO.ADR ;FIN CALL?
JRST UOEND ;YES. FINISH RECORD
MOVE T1,IO.TYP ;GET DATA TYPE
CAIN T1,TP%CHR ;CHARACTER?
JRST UOCHR ;YES
SETZM RECREM ;CLEAR CHAR REMAINDER
MOVE T1,IO.SIZ ;GET DATA SIZE
CAME T1,IO.INC ;IS IT THE SIMPLE CASE?
JRST UOWRD ;NO. MUST BE DONE WORD BY WORD
IMUL T1,IO.NUM ;CALC # WORDS
MOVEM T1,IO.SIZ ;SAVE AS DATA SIZE
MOVEI T1,1 ;SET DATA COUNT TO 1
MOVEM T1,IO.NUM
SETZM IO.INC ;WITH NO INCREMENT
JRST UOBLP ;GO DO THE BLT
UOWRD: MOVN T1,IO.SIZ ;ACCOUNT FOR THE INCREMENT
ADDM T1,IO.INC ;DONE FOR EACH ENTRY AUTOMATICALLY
UOBLP: MOVE T1,IO.SIZ ;GET ENTRY SIZE
MOVEM T1,LOCSIZ ;SAVE LOCALLY
UOBLP1: SKIPG RECLEN ;ANY ROOM LEFT IN RECORD?
$ECALL ETL,%POPJ ;NO. WARN USER AND DON'T OUTPUT MORE
DMOVE P1,OPTR(D) ;GET PNTR/COUNT
IDIV P2,BPW(D) ;GET # WORDS LEFT
JUMPG P2,UOBLT ;OK IF WE HAVE ROOM IN WINDOW
PUSHJ P,UOALIN ;NO ROOM. ALIGN THE PNTR/COUNT
LOAD T0,MODE(D) ;GET MODE
CAIE T0,MD.IMG ;BINARY?
PUSHJ P,OLSCWX ;YES. FINISH START OR CONTINUE LSCW
PUSHJ P,ONXTW ;OUTPUT CURRENT WINDOW, GET NEXT
LOAD T0,MODE(D) ;GET DATA MODE
CAIE T0,MD.IMG ;BINARY?
PUSHJ P,OLSCW2 ;YES. OUTPUT TYPE 2 LSCW
DMOVE P1,OPTR(D) ;GET PNTR/COUNT AGAIN
IDIV P2,BPW(D) ;GET # WORDS IN WINDOW
UOBLT: MOVE T2,LOCSIZ ;GET MIN OF ARRAY LENGTH
CAILE T2,(P2) ; AND WINDOW LENGTH
MOVEI T2,(P2)
CAMLE T2,RECLEN ; AND RECORD LENGTH
MOVE T2,RECLEN
;IO.ADR/ addr. of user's array.
;p1/ local FOROTS address of data.
;T2/ # words to copy
MOVE T1,IO.ADR ;GET USER'S ARRAY ADDRESS
TLNN T1,-1 ;User's array in a non-zero section?
JRST UOBLT2 ;No, normal BLT
MOVE T3,T2 ;COPY # WORDS TO COPY
MOVE T4,T1 ;T4/ "from" -- user's array
MOVEI T5,(P1) ;GET LOCAL ADDR
XMOVEI T5,1(T5) ;T5/ "to"-- get Global FOROTS' address.
EXTEND T3,[XBLT] ;** COPY array **
JRST UOSKP
;Use BLT
UOBLT2: MOVSI T4,(T1) ;GET BLT-FROM ADDRESS
HRRI T4,1(P1) ;AND BLT-TO ADDRESS
MOVEI T3,(P1) ;GET ADDR-1 OF 1ST WORD IN WINDOW
ADDI T3,(T2) ;POINT TO END OF BLT
BLT T4,(T3) ;MOVE DATA INTO WINDOW
UOSKP: ADDI P1,(T2) ;INCREMENT ADDRESS OF DATA IN WINDOW
HXL P1,BYTPT(D) ;WORD-ALIGN IT
SUBI P2,(T2) ;DECREMENT COUNT OF DATA LEFT IN WINDOW
IMUL P2,BPW(D) ;GET # CHARS
DMOVEM P1,OPTR(D) ;SAVE THEM BOTH
ADDM T2,IO.ADR ;INCREMENT DATA ADDRESS
MOVNI T2,(T2) ;GET NEG # WORDS TRANSFERRED
ADDM T2,RECLEN ;AND RECORD LENGTH
ADDB T2,LOCSIZ ;AND NUMBER OF WORDS OF DATA
JUMPG T2,UOBLP1 ;IF SOME LEFT, CONTINUE
MOVE T1,IO.INC ;GET INCREMENT
ADDM T1,IO.ADR ;ADD TO DATA ADDRESS
SOSLE T1,IO.NUM ;DECR COUNT
JRST UOBLP ;MORE TO DO
POPJ P, ;ELSE, LEAVE
UOCHR: MOVE T1,RECLEN ;GET # WORDS LEFT IN RECORD
IMUL T1,BPW(D) ;GET # CHARS
ADD T1,RECREM ;ADD PREVIOUS REMAINDER
MOVEM T1,LOCREC ;SAVE LOCAL RECORD LENGTH
JUMPE T1,UOCZER ;DONE IF NONE LEFT
MOVE T1,IO.SIZ ;GET SIZE
CAME T1,IO.INC ;SIMPLE CASE?
JRST UOCHR1 ;NO. DO IT CHAR BY CHAR
IMUL T1,IO.NUM ;GET TOTAL # CHARS
MOVEM T1,IO.SIZ ;MAKE IT LOOK LIKE 1 BIG VARIABLE
MOVEI T1,1 ;DATA COUNT OF 1
MOVEM T1,IO.NUM
SETZM IO.INC ;NO INCREMENT NECESSARY
JRST UOCBLP ;GO DO THE BLT
UOCHR1: MOVN T1,IO.SIZ ;ACCOUNT FOR THE INCREMENT DONE
ADDM T1,IO.INC ;DONE FOR EACH ENTRY AUTOMATICALLY
UOCBLP: MOVE T1,IO.SIZ ;GET ENTRY SIZE
MOVEM T1,LOCSIZ ;SET UP LOCAL ONE
UOCBL1: SKIPG LOCREC ;ANY ROOM LEFT IN RECORD?
JRST UOCZER ;NO. DONE
SKIPLE OCNT(D) ;ANY CHARS IN WINDOW
JRST UOCBLT ;YES. GO TRANSFER SOME
LOAD T0,MODE(D) ;GET DATA MODE
CAIE T0,MD.IMG ;BINARY?
PUSHJ P,OLSCWX ;YES. FINISH START OR CONTINUE LSCW
PUSHJ P,ONXTW ;OUTPUT CURRENT WINDOW, GET NEXT
LOAD T0,MODE(D) ;GET DATA MODE
CAIE T0,MD.IMG ;BINARY?
PUSHJ P,OLSCW2 ;YES. OUTPUT TYPE 2 LSCW
UOCBLT: MOVE T0,OCNT(D) ;GET MINIMUM OF WINDOW COUNT
CAMLE T0,LOCREC ;AND CHARS IN RECORD
MOVE T0,LOCREC
CAMLE T0,LOCSIZ ;AND NUMBER OF CHARS TO TRANSFER
MOVE T0,LOCSIZ
MOVEM T0,LOCNUM ;SAVE IT
MOVE T1,IO.ADR ;GET THE DATA PNTR
MOVE T3,T0 ;COPY THE COUNT
MOVE T4,OPTR(D) ;GET DEST PNTR
EXTEND T0,[EXP MOVSLJ,0] ;MOVE STRING LEFT-JUSTIFIED, ZERO FILL
$SNH ;SHOULD SKIP RETURN
MOVEM T4,OPTR(D) ;UPDATE BUFFER PNTR
MOVE T1,LOCNUM ;GET # CHARS TRANSFERRED
ADJBP T1,IO.ADR ;ADJUST - UPDATED PNTR IS 2-WORD!
MOVEM T1,IO.ADR ;SAVE UPDATED PNTR
MOVN T1,LOCNUM ;GET NEGATIVE CHARS TRANSFERRED
ADDM T1,LOCREC ;UPDATE # CHARS LEFT IN RECORD
ADDM T1,OCNT(D) ;UPDATE # CHARS LEFT IN WINDOW
ADDB T1,LOCSIZ ;UPDATE # CHARS TO TRANSFER
JUMPG T1,UOCBL1 ;LOOP IF MORE TO TRANSFER
SKIPN T1,IO.INC ;GET INCREMENT
JRST UOCNI ;NONE
ADJBP T1,IO.ADR ;UPDATE PNTR
MOVEM T1,IO.ADR ;AND SAVE IT
UOCNI: SOSLE IO.NUM ;ANY MORE ENTRIES?
JRST UOCBLP ;YES. GO DO THEM
MOVE T1,LOCREC ;GET LOCAL RECORD LENGTH LEFT
IDIV T1,BPW(D) ;GET WORDS AND BYTES
DMOVEM T1,RECLEN ;SAVE FOR NEXT CALL
POPJ P,
;HERE IF NO ROOM LEFT IN RECORD BUT THE IOLST HAS SPECIFIED
;MORE OUTPUT. GIVE THE USER AN WARNING MESSAGE AND CLEAR THE
;RECORD COUNTS.
UOCZER: $ECALL ETL ;ATTEMPT TO WRITE BEYOND FIXED-LENGTH RECORD
SETZM RECLEN ;CLEAR ALL LENGTHS
SETZM RECREM
POPJ P,
UOEND: SKIPN RSIZE(D) ;RECORD SIZE?
JRST UOXYZ ;NO, FINE
PUSHJ P,UOALIN ;WORD-ALIGN THE PNTR/COUNT
MOVE P3,RECLEN ;GET ROOM LEFT IN RECORD
JUMPLE P3,UOXYZ ;NO ZEROS NECESSARY, FINE
SETZ T1, ;GET A ZERO
PUSHJ P,OAWORD ;PUT IN FILE
SOJG P3,.-1 ;PAD WHOLE RECORD
UOXYZ: PUSHJ P,OLSCW3 ;OUTPUT END LSCW OR CLEAR END OF WORD
MOVE T1,BYTN(D) ;GET BYTE # OF NEXT WINDOW
SUB T1,OCNT(D) ;GET LAST BYTE IN USE
MOVE T0,FLAGS(D) ;Fetch DDB flags
TXNE T0,D%RAN ;RANDOM FILE?
CAMLE T1,EOFN(D) ;YES. ONLY STORE LARGER EOFN
MOVEM T1,EOFN(D) ;SAVE AS EOF PNTR
PJRST %SETAV ;RETURN TO USER PROG
;LSCW ROUTINES
;FORMAT OF BINARY RECORD: (FORMAT OF BINARY RECORD)
;THERE IS NO NECESSARY RELATIONSHIP BETWEEN SEGMENT SIZE AND BUFFER SIZE
OLSCW1: SKIPE RSIZE(D) ;IS RECORD SIZE SPECIFIED?
JRST O1FIX ;YES - SET TYPE 1 LSCW NOW
SETZM SEGCNT ;CLEAR WORD COUNT OF SEGMENTS ALREADY IN FILE
MOVSI T1,(1B8) ;GET START LSCW
JRST O2FIX ;SKIP TYPE 2 PROCESSING
OLSCW2: SKIPE RSIZE(D) ;IS RECORD SIZE SPECIFIED?
POPJ P, ;YES - NO NEED FOR TYPE 2 LSCW
MOVSI T1,(2B8) ;GET CONTINUE LSCW
O2FIX: PUSHJ P,OWORD ;PUT WORD INTO FILE WINDOW
HRRZM P1,CWADR ;STORE IN-CORE ADDRESS OF CONTROL WORD
POPJ P,
O1FIX: MOVE T1,RSIZE(D) ;GET RECORD SIZE, WORDS
ADD T1,[1B8+1] ;SET START LSCW
SETZM CWADR ;REMEMBER WE'VE ALREADY FILLED IN START LSCW
PJRST OWORD ;AND PUT WORD INTO FILE WINDOW
OLSCWX: SKIPE RSIZE(D) ;WAS RECORD SIZE SPECIFIED?
POPJ P, ;YES - START LSCW WAS ALREADY FILLED IN
SKIPN T2,CWADR ;GET ADDRESS OF TYPE 1 OR 2 CONTROL WORD
$SNH ;Already out in file, bug
HRRZ T1,OPTR(D) ;POINT TO LAST WORD WRITTEN
SUBI T1,-1(T2) ;GET DISTANCE FROM CONTROL WORD = SEG LENGTH
HRRM T1,(T2) ;STORE LENGTH IN CONTROL WORD
ADDM T1,SEGCNT ;ADD INTO TOTAL RECORD LENGTH
SETZM CWADR ;NOW NO CONTROL WORD WAITING TO BE FINISHED
POPJ P, ;DONE
OLSCW3: LOAD T0,MODE(D) ;GET DATA MODE
CAIN T0,MD.IMG ;BINARY?
JRST OCLR ;NO. JUST CLEAR CHARS IN END OF CURRENT WORD
SKIPE RSIZE(D) ;WAS RECORD SIZE SPECIFIED?
JRST O3FIX ;YES - START LSCW ALL DONE - DO TYPE 3 ONLY
SKIPN T2,CWADR ;GET ADDRESS OF TYPE 1 OR 2 CONTROL WORD
$SNH ;Already out in file, bug
HRRZ T1,OPTR(D) ;POINT TO LAST WORD WRITTEN
SUBI T1,-1(T2) ;GET DISTANCE FROM CONTROL WORD = SEG LENGTH
HRRM T1,(T2) ;STORE LENGTH IN START CONTROL WORD
ADD T1,SEGCNT ;ADD IN WORDS FROM OTHER SEGMENTS
ADDI T1,1 ;ADD IN END LSCW TOO
ADD T1,[3B8] ;PUT IN TYPE-3 LSCW HEADER
SETZM CWADR ;NOW NO CONTROL WORD WAITING TO BE FINISHED
PJRST OWORD ;PUT INTO FILE
O3FIX: MOVE T1,RSIZE(D) ;GET USER SPECIFIED RECORD SIZE
ADD T1,[3B8+2] ;SET UP END LSCW
PJRST OWORD ;PUT INTO FILE
UOALIN: HRRZ T1,OPTR(D) ;GET LOCAL PNTR
MOVE T2,OCNT(D) ;GET COUNT
IDIV T2,BPW(D) ;ALIGN THE COUNT
JUMPE T3,%POPJ ;PNTR/COUNT ALREADY ALIGNED
IMUL T2,BPW(D)
LDB T3,[POINT 6,OPTR(D),5] ;GET # BITS TO RIGHT
MOVE T3,RGTMSK(T3) ;GET A MASK
ANDCAM T3,(T1) ;CLEAR THE BITS
HXL T1,BYTPT(D) ;ALIGN THE PNTR
DMOVEM T1,OPTR(D)
POPJ P,
;OCLR - AT END OF EACH WRITE TO CLEAR THE REMAINING CHARACTERS IN
;THE CURRENT WORD, IF ANY.
OCLR: HRRZ T1,OPTR(D) ;GET LOCAL PNTR
MOVE T2,OCNT(D) ;GET COUNT
IDIV T2,BPW(D) ;ALIGN THE COUNT
JUMPE T3,%POPJ ;PNTR/COUNT ALREADY ALIGNED
LDB T3,[POINT 6,OPTR(D),5] ;GET # BITS TO RIGHT
MOVE T3,RGTMSK(T3) ;GET A MASK
ANDCAM T3,(T1) ;CLEAR THE BITS
POPJ P,
;OAWORD - TO OUTPUT A WORD TO THE FILE, WITH THE ASSUMPTION THAT
;THE BYTE POINTER/COUNT HAVE ALREADY BEEN WORD-ALIGNED.
OANXT: MOVEM T1,TOWORD ;SAVE WORD TO OUTPUT
PUSHJ P,ONXTW ;NOTHING LEFT, GO MAP NEXT WINDOW
MOVE T1,TOWORD ;GET WORD BACK AGAIN
OAWORD: SKIPG OCNT(D) ;ANY WORDS LEFT?
JRST OANXT ;NO. OUTPUT A WINDOW
MOVN P2,BPW(D) ;REDUCE BY BYTES
ADDM P2,OCNT(D)
AOS P1,OPTR(D) ;INCR PNTR BY A WORD
MOVEI P1,(P1) ;GET JUST LOCAL ADDR
MOVEM T1,(P1) ;OUTPUT THE DATA
POPJ P,
ONXT: MOVEM T1,TOWORD ;SAVE WORD TO OUTPUT
PUSHJ P,ONXTW ;NOTHING LEFT, GO MAP NEXT WINDOW
MOVE T1,TOWORD ;GET WORD BACK AGAIN
OWORD: SKIPG P2,OCNT(D) ;GET THE COUNT
JRST ONXT ;NO ROOM. OUTPUT A BUFFERFUL
HRRZ P1,OPTR(D) ;GET THE LOCAL PNTR
IDIV P2,BPW(D) ;ALIGN THE COUNT
JUMPE P3,OWNC ;NOTHING TO CLEAR IF NO REMAINDER
LDB P3,[POINT 6,OPTR(D),5] ;GET # BITS TO THE RIGHT
MOVE P3,RGTMSK(P3) ;GET A MASK
ANDCAM P3,(P1) ;CLEAR THE BITS
JUMPN P2,OWNC ;CHECK IF WORD LEFT
SETZM OCNT(D) ;CLEAR COUNT, DO OUTPUT IF NOT
JRST ONXT
OWNC: SUBI P2,1 ;DECR WORD COUNT
ADDI P1,1 ;INCR THE PNTR
MOVEM T1,(P1) ;OUTPUT THE WORD
HXL P1,BYTPT(D) ;MAKE IT A CHARACTER BYTE PNTR AGAIN
IMUL P2,BPW(D) ;AND MAKE THE COUNT IN BYTES
DMOVEM P1,OPTR(D) ;SAVE THEM BOTH
POPJ P,
%RTMSK:
RGTMSK: 0
1
3
7
17
37
77
177
377
777
1777
3777
7777
17777
37777
77777
177777
377777
777777
1,,-1
3,,-1
7,,-1
17,,-1
37,,-1
77,,-1
177,,-1
377,,-1
777,,-1
1777,,-1
3777,,-1
7777,,-1
17777,,-1
37777,,-1
77777,,-1
177777,,-1
377777,,-1
777777,,-1
SEGMENT DATA
RECLEN: BLOCK 1 ;RECORD OR SEGMENT LENGTH IN WORDS
RECREM: BLOCK 1 ;CHARACTER REMAINDER
LOCREC: BLOCK 1 ;RECORD OR SEGMENT LENGTH IN CHARACTERS
LOCNUM: BLOCK 1 ;LOCAL # WORDS OR CHARS TO TRANSFER
LOCSIZ: BLOCK 1 ;LOCAL CHARACTER SIZE
CWADR: BLOCK 1 ;ADDRESS OF START LSCW
SEGCNT: BLOCK 1 ;COUNT OF WORDS OUT IN FILE IN PREVIOUS SEGMENTS
TOWORD: BLOCK 1 ;TEMP FOR OUTPUT WORD
SUBTTL DUMP MODE I/O
SEGMENT CODE
IF20,<
DMPIN: POPJ P,
DMPOUT: POPJ P,
DMPSET: POPJ P,
>;END IF20
IF10,<
DMPIN: SKIPE IO.ADR ;ANY I/O ADDR?
JRST LSTDMP ;YES. ACCUMULATE IT
HRRZ T1,DMPNTR ;GET PNTR TO LIST
SETZM (T1) ;CLEAR LAST WORD
MOVEI T2,.FOINP ;SET FOR INPUT
HLL T2,FBLK(D) ;Get channel stuff
MOVEI T3,DMPLST
MOVE T1,[2,,T2]
FILOP. T1, ;Do the INPUT
PUSHJ P,EOFCHK ;Set D%END if EOF; else give error
MOVE T1,FLAGS(D) ;Get flags
TXNE T1,D%END ;End of file?
$ECALL EOF,%ABORT ;Yes, give error
JRST %SETAV ;NO. RETURN
DMPOUT: SKIPE IO.ADR ;ANY I/O ADDR?
JRST LSTDMP ;YES. ACCUMULATE IT
HRRZ T1,DMPNTR ;GET PNTR TO LIST
SETZM (T1) ;CLEAR LAST WORD
MOVEI T2,.FOOUT ;SET FOR OUTPUT
HLL T2,FBLK(D) ;GET CHANNEL STUFF
MOVEI T3,DMPLST
MOVE T1,[2,,T2]
FILOP. T1, ;DO THE OUTPUT
$ECALL IOE,%ABORT ;Error
JRST %SETAV ;RETURN PROPERLY
DMPSET: MOVE T1,[-MAXARG,,DMPLST] ;SETUP DUMP MODE LIST PNTR
MOVEM T1,DMPNTR
POPJ P,
LSTDMP: MOVE T1,IO.ADR ;GET I/O ADDR
SUBI T1,1 ;GET ADDR-1
SKIPN T2,IO.INC ;GET INCREMENT
JRST INCOK ;ZERO IS OK
CAME T2,IO.SIZ ;SAME AS SIZE?
$ECALL IDI ;ILLEGAL DUMP-MODE I/O LIST
INCOK: MOVE T3,IO.SIZ ;GET SIZE
IMUL T3,IO.NUM ;GET # WORDS
MOVNI T2,(T3) ;NEGATIVE
HRLI T1,(T2) ;IN LEFT HALF
MOVE T2,DMPNTR ;GET THE PNTR
MOVEM T1,(T2) ;SAVE IN DUMP MODE LIST
AOBJN T2,.+2 ;INCR
$ECALL DLL ;DUMP I/O LIST TOO LONG
MOVEM T2,DMPNTR ;SAVE INCREMENTED PNTR
ADDI T3,177 ;GET # BLOCKS
IDIVI T3,200 ;ROUNDED UP
ADDM T3,BLKN(D) ;ADD TO BLOCK COUNT
POPJ P,
>;END IF10
SUBTTL DISK POSITIONING
COMMENT &
TOPS-20 sequential disk files are read with PMAPs by moving a n-page window
through the file. The file window always starts on a n-page boundary and is
moved only when the desired byte is not in the window. The first process page
number of the window is in WPTR(D). (The window size can be set to something
besides 4 pages with BUFFERCOUNT=).
TOPS-20 and TOPS-10 random files are similar, but there are n independent
one-page windows. If references to the file are well localized, the
windows will often contain the desired records. For random files WTAB
contains a pointer to a n-word table, with each word giving the corresponding
file page number of a window. The number of pages
can be set with BUFFERCOUNT=. On TOPS-10, PFTAB is an n-word table
of flags of whether the page has been modified.
TOPS-10 sequential disk files are like any other TOPS-10 sequential file.
&
;ROUTINE TO MAP NEXT WINDOW OF FILE
;ARGS: BYTN = FILE BYTE NUMBER OF START OF WINDOW
;RETURN: P1 = BYTE POINTER TO FIRST MAPPED BYTE
; P2 = COUNT OF BYTES IN WINDOW
; BYTN = FILE BYTE NUMBER+1 OF END OF WINDOW
; I.E., STARTING BYTE OF FOLLOWING WINDOW
INXTW: MOVE T0,FLAGS(D) ;GET DDB FLAGS
TXNE T0,D%RAN ;RANDOM?
JRST IMAPW ;YES
ISNXTW: TXNE T0,D%END ;END OF FILE ALREADY?
POPJ P, ;YES. JUST LEAVE
LOAD T0,INDX(D) ;GET DEVICE INDEX
CAIE T0,DI.DSK ;DISK?
JRST ISBUF ;NO
PJRST %ISMAP ;MAP NEXT WINDOW OF SEQUENTIAL FILE
ONXTW: MOVE T1,BYTN(D) ;GET # BYTES WRITTEN SO FAR
CAMLE T1,EOFN(D) ;UPDATE EOF PNTR IF GREATER
MOVEM T1,EOFN(D)
MOVE T0,FLAGS(D) ;GET DDB FLAGS
TXNE T0,D%RAN ;RANDOM?
JRST OMAPW ;YES
OSNXTW: LOAD T0,INDX(D) ;GET DEVICE INDEX
LOAD T1,ACC(D) ;GET ACCESS
CAIE T1,AC.APP ;APPEND?
CAIE T0,DI.DSK ;DISK?
JRST OSBUF ;APPEND OR NON-DISK
PJRST %OSMAP ;MAP NEXT WINDOW
;ROUTINE TO GET NEXT BUFFER OF NON-DISK FILE
IF20,<
ISBUF: SKIPE B36FLG(D) ;OPENED IN 36-BIT MODE?
JRST BISBUF ;YES. DO BINARY INPUT
LOAD T1,IJFN(D) ;GET FILE JFN
MOVE T2,WADR(D) ;GET POINTER TO BUFFER
SUBI T2,1 ;POINT TO WORD-1
HXL T2,BYTPT(D) ;GET END-OF-WORD BYTE PNTR
MOVN T3,WSIZ(D) ;GET WINDOW SIZE IN BYTES
SINR% ;READ STRING
ERCAL EOFCHK ;ERROR, POSSIBLE EOF
MOVE T2,WADR(D) ;MAKE BYTE POINTER TO BUFFER
SUBI T2,1 ;POINT TO BEG-1
HXL T2,BYTPT(D)
ADD T3,WSIZ(D) ;CALC # BYTES WE GOT
ADDM T3,BYTN(D) ;ADD TO # BYTES READ IN FILE
DMOVEM T2,IPTR(D) ;SAVE PNTR/COUNT
POPJ P,
BISBUF: MOVE T0,FLAGS(D) ;GET DDB FLAGS
TXNE T0,D%END ;END FILE ALREADY?
POPJ P, ;YES. NOTHING TO DO
LOAD T1,IJFN(D) ;GET JFN
MOVE T2,WADR(D) ;GET ADDRESS OF BUFFER
HRLI T2,(POINT 36) ;GET BINARY POINTER
MOVN T3,WSIZ(D) ;GET WINDOW SIZE
IDIV T3,BPW(D) ;GET # WORDS
SINR% ;READ
ERCAL EOFCHK ;EOF OR ERROR
IMUL T3,BPW(D) ;GET LEFTOVERS IN BYTES
MOVE T2,WADR(D) ;POINT TO DATA
SUBI T2,1 ;POINT TO WORD-1
HXL T2,BYTPT(D) ;ALIGN THE PNTR
ADD T3,WSIZ(D) ;CALC # BYTES WE GOT
ADDM T3,BYTN(D) ;ADD TO # BYTES WE'VE READ IN FILE
DMOVEM T2,IPTR(D) ;SAVE PNTR/COUNT
POPJ P, ;DONE
EOFCHK: MOVEI T1,.FHSLF ;THIS FORK
GETER% ;GET LAST ERROR
MOVEI T2,(T2) ;TOSS THE HANDLE
CAIE T2,IOX4 ;EOF?
$ECALL IOE,%ABORT ;NO. REPORT ERROR
MOVX T0,D%END ;EOF, tell caller
IORM T0,FLAGS(D)
POPJ P,
;NON-DISK OUTPUT
OSBUF: PUSHJ P,%OBUF ;OUTPUT BUFFERFUL
JRST OSKP ;AND SETUP BUFFER PNTR/COUNT
%OBUF: SKIPE B36FLG(D) ;OPENED IN 36-BIT MODE?
JRST BOSBUF ;YES. DO BINARY OUTPUT
SKIPN OPTR(D) ;IF NO CHARS, JUST PREPARE WINDOW
POPJ P,
LOAD T1,OJFN(D) ;GET JFN
MOVE T2,WADR(D) ;GET WINDOW ADDR
SUBI T2,1 ;POINT TO WORD-1
HXL T2,BYTPT(D) ;GET END-OF-WORD BYTE PNTR
MOVE T3,WSIZ(D) ;GET WINDOW SIZE IN BYTES
SUB T3,OCNT(D) ;DECREMENT ACTIVE BYTE COUNT
ADDM T3,BYTN(D) ;UPDATE # BYTES WRITTEN IN FILE
MOVN T3,T3 ;GET NEGATIVE
SOUTR% ;OUTPUT THE BLOCK
ERJMP OUTERR ;ERROR, GO TELL USER
POPJ P,
BOSBUF: SKIPN OPTR(D) ;IF FIRST BUFFER
POPJ P, ;DON'T DO OUTPUT
LOAD T1,IJFN(D) ;GET JFN
MOVE T2,WADR(D) ;GET ADDRESS OF BUFFER
HRLI T2,(POINT 36) ;GET BINARY BYTE POINTER
MOVE T3,WSIZ(D) ;GET WINDOW SIZE IN BYTES
SUB T3,OCNT(D) ;CALC # BYTES USED
ADDM T3,BYTN(D) ;UPDATE # BYTES WRITTEN IN FILE
IDIV T3,BPW(D) ;GET IT IN WORDS
JUMPE T4,BOSOUT ;IF WORD-ALIGNED, JUST DO SOUTR
ADDI T3,1 ;ELSE ADD 1 TO WORD COUNT
HRRZ T4,OPTR(D) ;GET LOCAL PNTR
LDB T5,[POINT 6,OPTR(D),5] ;GET # BITS TO CLEAR
MOVE T5,%RTMSK(T5) ;GET THE MASK
ANDCAM T5,(T4) ;CLEAR THE BITS
BOSOUT: MOVN T3,T3 ;GET COUNT NEGATIVE
SOUTR% ;WRITE BUFFER
ERJMP OUTERR ;ERROR, TYPE MESSAGE
POPJ P,
OSKP: MOVE T1,WADR(D) ;POINT TO EMPTY BUFFER
SUBI T1,1 ;POINT TO WORD-1
HXL T1,BYTPT(D) ;CREATE PNTR
MOVE T2,WSIZ(D) ;GET FULL WINDOW SIZE
DMOVEM T1,OPTR(D) ;SAVE PNTR/COUNT
ADD T2,BPW(D) ;ROUND WINDOW SIZE UP TO WORDS
SUBI T2,1
IDIV T2,BPW(D) ;GET # WORDS IN WINDOW
ADD T2,WADR(D) ;POINT TO END OF WINDOW+1
MOVE T1,WADR(D) ;GET WINDOW ADDR
SETZM (T1) ;CLEAR 1ST WORD
HRLI T1,(T1) ;MAKE IT BLT PNTR
ADDI T1,1
BLT T1,-1(T2) ;CLEAR BUFFER
POPJ P, ;DONE
OUTERR: $ECALL IOE,%ABORT ;GENERAL I/O ERROR
> ;END IF20
;ROUTINE TO MAP WINDOW CONTAINING FIRST BYTE OF RANDOM RECORD
;THINGS ARE LEFT SET UP FOR NXTW IN CASE RECORD SPANS WINDOWS
;ARGS: A.REC = RECORD NUMBER TO SET TO
;RETURN: IPTR/OPTR = POINTER TO FIRST BYTE OF RECORD
; ICNT/OCNT = BYTES IN WINDOW
; BYTN = NUMBER OF FIRST BYTE IN FOLLOWING WINDOW
FIRMPW: PUSHJ P,FRMAPW ;SETUP DESIRED BYTE NUMBER
JRST IRMPW ;GO CHECK IF EOF
FORMPW: PUSHJ P,FRMAPW ;SETUP DESIRED BYTE NUMBER
PJRST OMAPW ;AND MAP IT
UIRMPW: PUSHJ P,URMAPW ;SETUP DESIRED BYTE NUMBER
IRMPW: MOVE T1,BYTN(D) ;GET BYTE NUMBER OF RECORD START
CAMGE T1,EOFN(D) ;PAST EOF?
PJRST IMAPW ;NO. MAP IT
AOS CREC(D) ;INCR RECORD NUMBER FOR MSG
$ECALL RNR,%ABORT ;YES. RECORD NOT WRITTEN
UORMPW: PUSHJ P,URMAPW ;SETUP DESIRED BYTE NUMBER
PJRST OMAPW ;AND MAP IT
FRMAPW: SKIPA T2,FRSIZB(D) ;GET FORMATTED RECORD SIZE
URMAPW: MOVE T2,URSIZB(D) ;GET UNFORMATTED RECORD SIZE
RMAPW: SKIPG T1,@A.REC ;GET RECORD NUMBER
; IOERR (IRN,25,512,?,Illegal record number $D,<T1>,%ABORT)
$ECALL IRN,%ABORT
SUBI T1,1 ;GET # RECS BEFORE THIS ONE
MOVEM T1,CREC(D) ;STORE PREVIOUS RECORD NUMBER
IMUL T1,T2 ;GET # BYTES BEFORE THIS ONE
MOVEM T1,BYTN(D) ;WHICH IS THE BYTE NUMBER OF REC BEG
POPJ P,
;ROUTINE TO MAP A FILE WINDOW FOR A RANDOM FILE
;ARGS: BYTN = FILE ADDRESS
;RETURN: IPTR/OPTR = PROCESS BYTE POINTER
; ICNT/OCNT = NUMBER OF BYTES LEFT IN WINDOW
LWSIZ==9 ;A PAGE IS
PSIZ==1000 ;A PAGE IS A PAGE IS A PAGE
IMAPW: PUSHJ P,%SAVE2 ;SAVE P1,P2
PUSHJ P,GETPAG ;GET PAGE, SETUP PNTR/COUNT
DMOVEM P1,IPTR(D) ;SAVE PNTR/COUNT
PUSHJ P,PAGCHK ;CHECK THE PAGE
PUSHJ P,MAPUPD ;UPDATE NEXT PAGE TO CHANGE
POPJ P,
OMAPW: PUSHJ P,%SAVE2 ;SAVE P1,P2
PUSHJ P,GETPAG ;GET PAGE, SETUP PNTR/COUNT
DMOVEM P1,OPTR(D) ;SAVE PNTR/COUNT
PUSHJ P,SETWRT ;FLAG PAGE IS WRITTEN
PUSHJ P,MAPUPD ;UPDATE NEXT PAGE TO CHANGE
POPJ P,
GETPAG: MOVE P1,BYTN(D) ;GET BYTE NUMBER
IDIV P1,WSIZ(D) ;GET PAGE #
MOVE T1,WTAB(D) ;GET POINTER TO WINDOW TABLE
LOAD T2,BUFCT(D)
FINDW: CAMN P1,(T1) ;MATCH?
JRST PAGMAT ;YES
ADDI T1,1 ;INCR TABLE PNTR
SOJG T2,FINDW ;LOOP
PUSHJ P,RDW ;NOT IN CORE
PAGMAT: MOVE P1,T1 ;GET PNTR TO CORRECT ENTRY IN LIST
SUB P1,WTAB(D) ;GET PAGE OFFSET
MOVEM P1,WPAGE ;SAVE IT
ADD P1,WPTR(D) ;GET CORRESPONDING CORE PAGE #
LSH P1,LWSIZ ;MAKE IT A WORD ADDR
SUBI P1,1 ;SHOULD POINT AT DESIRED WORD -1
HXL P1,BYTPT(D) ;MAKE IT A BYTE PNTR
MOVE T2,WSIZ(D) ;GET # BYTES IN WINDOW
SUBI T2,(P2) ;GET # BYTES AVAILABLE
EXCH P1,P2 ;PUT THE BYTE REMAINDER IN P1
ADJBP P1,P2 ;UPDATE THE BYTE PNTR
MOVEI P2,(T2) ;GET BYTES AVAILABLE WHERE IT SHOULD BE
ADDM P2,BYTN(D) ;SET BYTE NUMBER TO AFTER THIS WINDOW
POPJ P,
MAPUPD: MOVE T2,WADR(D) ;GET REFILL POINTER TO WINDOW TABLE
CAME T2,WPAGE ;IS IT POINTING TO PAGE WE JUST USED?
POPJ P, ;NO. LEAVE IT WHERE IT IS
SOJGE T2,PTRRET ;YES. POINT IT 1 BEHIND THIS ONE
LOAD T2,BUFCT(D) ;PASSED BEGINNING OF TABLE. POINT TO END
SUBI T2,1
PTRRET: MOVEM T2,WADR(D) ;RESET REFILL POINTER
POPJ P,
SEGMENT DATA
WPAGE: BLOCK 1 ;OFFSET INTO WTAB FOR MATCHED PAGE #
SEGMENT CODE
IF10,<
SETWRT: MOVE T2,WPAGE ;GET PAGE OFFSET
ADD T2,PFTAB(D) ;POINT TO MODIFIED PAGE TABLE
SETOM (T2) ;SET PAGE MODIFIED
POPJ P,
PAGCHK: POPJ P,
>;END IF10
IF20,<
PAGCHK: LOAD T3,ACC(D) ;GET ACCESS
CAIE T3,AC.RIN ;RANDIN?
JRST RECTPG ;NO. RANDOM. RECORD TOP PAGE
MOVE T2,WPAGE ;GET PAGE # IN QUESTION
ADD T2,WPTR(D)
LSH T2,LWSIZ ;MAKE IT AN ADDRESS
SKIP (T2) ;REFERENCE A WORD IN THE PAGE
ERJMP UNMAPR ;UNMAP THE PAGE IF NON-EXISTENT
POPJ P,
UNMAPR: LSH T2,-LWSIZ ;MAKE IT A PAGE AGAIN
HRLI T2,.FHSLF ;THIS FORK
SETO T1, ;SETUP UNMAP FUNCTION
SETZ T3, ;WITH NO REPEAT COUNT
PMAP% ;UNMAP IT, SO IT WILL BE 0
POPJ P,
SETWRT:
RECTPG: MOVE T1,WPAGE ;[3170] Get page offset in table
ADD T1,WTAB(D) ;POINT INTO TABLE
MOVE T2,(T1) ;GET FILE PAGE #
CAMLE T2,TPAGE(D) ;GREATER THAN ANY PAGE REFERENCED BEFORE?
MOVEM T2,TPAGE(D) ;YES. SAVE IT
POPJ P,
RDW: MOVE T2,WADR(D) ;GET PROCESS PAGE NUMBER
ADD T2,WPTR(D)
HRLI T2,.FHSLF ;FORK HANDLE
LOAD T1,IJFN(D) ;JFN
MOVSI T1,(T1)
HRRI T1,(P1) ;FILE PAGE NUMBER
MOVSI T3,(PM%PLD+PM%RD+PM%WR) ;ACCESS BITS
PMAP% ;MAP PAGE IN
ERJMP PGERR ;[3247]
MOVE T1,WADR(D) ;GET PAGE TABLE OFFSET AGAIN
ADD T1,WTAB(D) ;POINT INTO PAGE TABLE
MOVEM P1,(T1) ;STORE NEW FILE PAGE NUMBER
POPJ P, ;LEAVE WITH TABLE PNTR IN T1
>;END IF20
IF10,<
RDW: PUSHJ P,WRTPG ;WRITE PAGE BACK IF MODIFIED
CAMLE P1,TPAGE(D) ;WITHIN WRITTEN FILE?
JRST CLRPAG ;NO. CREATE ZEROS, ACT AS IF IT IS
HLLZ T2,CHAN(D) ;SET CHANNEL NUMBER
HRRI T2,.FOUSI ;SET USETI FUNCTION
MOVE T3,P1 ;GET PAGE NUMBER
IMULI T3,4 ;4 BLOCKS/PAGE
ADDI T3,1 ;MAKE IT A BLOCK NUMBER
MOVE T1,[2,,T2] ;SET TO DESIRED BLOCK
FILOP. T1,
$ECALL IOE,%ABORT
MOVE T4,WADR(D) ;GET PAGE TABLE OFFSET
ADD T4,WPTR(D) ;GET CORE PAGE NUMBER
LSH T4,LWSIZ ;CONVERT TO ADDRESS
MOVE T5,P1 ;GET FILE PAGE NUMBER AGAIN
ADDI T5,1 ;GET # PAGES
LSH T5,LWSIZ ;GET # WORDS IN THESE PAGES
CAMG T5,SIZ(D) ;BEYOND WRITTEN WORDS?
MOVE T5,SIZ(D) ;NO
SUB T5,SIZ(D) ;GET # WORDS BEYOND THOSE WRITTEN
JUMPE T5,RDWNC ;NOTHING TO CLEAR IF WITHIN FILE
MOVEI T1,(T4) ;COPY PAGE ADDRESS
ADDI T1,PSIZ ;POINT TO LAST ADDR OF PAGE + 1
SUBI T1,(T5) ;POINT TO 1ST WORD TO CLEAR
SETZM (T1) ;CLEAR IT
CAIG T5,1 ;MORE TO CLEAR?
JRST RDWNC ;NO
HRLI T1,(T1) ;MAKE IT A BLT PNTR
ADDI T1,1
BLT T1,PSIZ-1(T4) ;CLEAR THE REST OF THE BLOCK
RDWNC: ADDI T5,-PSIZ ;SET NEGATIVE # WORDS TO READ
HRLI T4,(T5) ;IN IOWD
SUBI T4,1 ;ADDR-1 FOR IOWD
SETZ T5, ;ZERO TO END COMMAND LIST
MOVEI T3,T4 ;SET ADDRESS OF COMMAND LIST
HLLZ T2,CHAN(D) ;SET CHANNEL NUMBER
HRRI T2,.FOINP ;SET INPUT FUNCTION
MOVE T1,[2,,T2] ;SET ARG BLOCK POINTER
FILOP. T1, ;DO FILOP
$ECALL IOE,%ABORT
MOVE T1,WADR(D) ;RELOAD WTAB POINTER
ADD T1,WTAB(D)
MOVEM P1,(T1) ;STORE NEW FILE PAGE NUMBER
POPJ P, ;LEAVE WITH TABLE PNTR IN T1
WRTPG: MOVE T1,WADR(D) ;GET PAGE TABLE OFFSET
ADD T1,PFTAB(D) ;POINT TO PAGE FLAG TABLE
SKIPL (T1) ;MODIFIED?
POPJ P, ;NOT MODIFIED, NO NEED TO WRITE
SETZM (T1) ;TURN OFF PAGE MODIFIED FLAG
HLLZ T2,CHAN(D) ;GET CHANNEL NUMBER
HRRI T2,.FOUSO ;SET USETO FUNCTION
MOVE T4,WADR(D) ;GET PAGE TABLE OFFSET TO THIS PAGE
ADD T4,WTAB(D) ;POINT INTO PAGE TABLE
MOVE T3,(T4) ;GET PAGE NUMBER
CAMLE T3,TPAGE(D) ;LARGER THAN TOP PAGE WRITTEN?
MOVEM T3,TPAGE(D) ;YES. RECORD IT
IMULI T3,4 ;4 BLOCKS/PAGE
ADDI T3,1 ;SET TO BLOCK #
MOVE T1,[2,,T2] ;SET ARG BLOCK POINTER
FILOP. T1, ;SET TO DESIRED BLOCK
$ECALL IOE,%ABORT
MOVE T3,(T4) ;GET PAGE NUMBER AGAIN
ADDI T3,1 ;GET # BLOCKS
IMUL T3,WSIZ(D) ;GET # BYTES TO END OF THIS BLOCK
CAMLE T3,EOFN(D) ;BEYOND EOF?
MOVE T3,EOFN(D) ;YES. USE EOF
ADD T3,BPW(D) ;ROUND UP TO # WORDS
SUBI T3,1
IDIV T3,BPW(D) ;GET # WORDS TO EOF
CAMLE T3,SIZ(D) ;BEYOND RECORDED LENGTH?
MOVEM T3,SIZ(D) ;YES. SAVE IN LOOKUP/ENTER BLOCK
ANDI T3,PSIZ-1 ;GET # WORDS TO WRITE
JUMPE T3,WRSBLK ;IF NO REMAINDER, WRITE FULL PAGE
MOVNI T3,(T3) ;GET NEGATIVE
JRST DOBWRT ;GO WRITE THE PAGE
WRSBLK: MOVNI T3,PSIZ ;STANDARD SIZE PAGE
DOBWRT: HLLZ T2,CHAN(D) ;GET CHANNEL NUMBER AGAIN
HRRI T2,.FOOUT ;SET OUTPUT FUNCTION
MOVE T4,WADR(D) ;POINT TO WTAB ENTRY AGAIN
ADD T4,WPTR(D) ;GET CORE PAGE ADDR
LSH T4,LWSIZ ;MAKE INTO WORD ADDRESS
SUBI T4,1 ;-1 FOR IOWD
HRLI T4,(T3) ;PUT COUNT IN LH
SETZ T5, ;ZERO TO END COMMAND LIST
MOVEI T3,T4 ;POINT TO COMMAND LIST
MOVE T1,[2,,T2] ;SET ARG BLOCK POINTER
FILOP. T1, ;DO FILOP OR OUT UUO
$ECALL IOE,%ABORT
POPJ P, ;DONE
CLRPAG: MOVE T1,WADR(D) ;GET OFFSET
ADD T1,WTAB(D) ;POINT INTO TABLE
MOVEM P1,(T1) ;STORE NEW FILE PAGE NUMBER
MOVE T2,WADR(D) ;GET PAGE OFFSET AGAIN
ADD T2,WPTR(D) ;GET CORE PAGE NUMBER
LSH T2,LWSIZ ;CONVERT TO AN ADDRESS
SETZM (T2) ;CLEAR THE 1ST WORD
MOVSI T3,(T2)
HRRI T3,1(T2)
BLT T3,PSIZ-1(T2) ;CLEAR THE REST
POPJ P, ;RETURN AS IF IT HAD RETURNED ZEROS
;HERE AT CLOSE TO WRITE MODIFIED PAGES
%RANWR: PUSHJ P,%SAVE1 ;SAVE P1
SETZM WADR(D) ;POINT TO BEG OF PAGE TABLE
LOAD P1,BUFCT(D) ;GET # PAGES
RWLP: PUSHJ P,WRTPG ;WRITE IT IF MODIFIED
AOS WADR(D) ;POINT TO NEXT PAGE
SOJG P1,RWLP ;DO ALL PAGES
POPJ P, ;DONE
> ;IF10
;SEQUENTIAL CASE, ONE N-PAGE WINDOW
;ARGS: BYTN = BYTE NUMBER IN FILE
; BUFCT = LENGTH OF WINDOW, PAGES
IF20,<
%OSMAP: PUSHJ P,%SAVE2 ;SAVE P1,P2
PUSHJ P,SMAPW ;MAP THE PAGE
PUSHJ P,SETPTR ;SETUP PNTR/COUNT
DMOVEM P1,OPTR(D) ;SAVE THE PNTR/COUNT
POPJ P,
%ISMAP: PUSHJ P,%SAVE2 ;SAVE P1,P2
MOVE T1,BYTN(D) ;GET DESIRED BYTE #
CAML T1,EOFN(D) ;PAST EOF?
JRST SMEOF ;YES. GO SET EOF FLAG
PUSHJ P,SMAPW ;MAP THE PAGE
PUSHJ P,CHKPGS ;CHECK PAGE EXISTENCE
PUSHJ P,SETPTR ;SETUP PNTR/COUNT
MOVE T2,BYTN(D) ;GET BYTE # OF NEXT WINDOW
CAMG T2,EOFN(D) ;PAST EOF?
JRST STCNT ;NO. GO STORE ACTIVE COUNT
SUB T2,EOFN(D) ;GET DIFF
SUBI P2,(T2) ;REDUCE # BYTES AVAIL
STCNT: DMOVEM P1,IPTR(D) ;SAVE PNTR/COUNT
POPJ P,
SMEOF: MOVX T1,D%END ;SET EOF
IORM T1,FLAGS(D)
POPJ P,
SMAPW: MOVE P1,BYTN(D) ;GET BYTE # IN FILE
MOVE T1,BPW(D) ;GET # BYTES/WORD
LSH T1,LWSIZ ;GET # BYTES/PAGE
IDIV P1,T1 ;GET PAGE #
MOVE T1,WPTR(D) ;GET PAGE ADDR OF BUFFER
MOVSI T2,.FHSLF ;THIS FORK
HRRI T2,(T1) ;PAGE NUMBER IN FORK
EXCH T1,P1 ;PAGE NUMBER IN FILE
LOAD T3,IJFN(D) ;JFN
HRLI T1,(T3)
LOAD T3,BUFCT(D) ;PAGE COUNT
HRLI T3,(PM%CNT+PM%PLD+PM%RD+PM%WR) ;ACCESS BITS, READ PAGES NOW
PMAP% ;MAP WINDOW INTO FILE
ERJMP PGERR ;[3247]
POPJ P,
CHKPGS: LOAD T4,BUFCT(D) ;GET BUFFER COUNT
MOVNI T4,(T4) ;NEGATIVE
MOVSI T4,(T4) ;IN LEFT HALF
HRR T4,WPTR(D) ;GET PAGE # OF BOTTOM PAGE
CHPLP: MOVEI T1,(T4) ;GET CORE ADDR
LSH T1,LWSIZ
SKIP (T1)
ERJMP UNMPG ;IF NOT THERE, GO UNMAP
AOBJN T4,CHPLP ;BACK FOR MORE
POPJ P, ;DONE
UNMPG: SETO T1, ;SET TO UNMAP IT
MOVSI T2,.FHSLF ;THIS FORK
HRRI T2,(T4) ;GET THE CORRECT PAGE TO TOSS
SETZ T3, ;NO REPEAT COUNT
PMAP% ;UNMAP THE PAGE
AOBJN T4,CHPLP ;BACK FOR MORE
POPJ P, ;DONE
SETPTR: LSH P1,LWSIZ ;MAKE IT A WORD ADDRESS
SUBI P1,1 ;POINT TO WORD ADDR-1
HXL P1,BYTPT(D) ;MAKE IT A BYTE PNTR
MOVE T2,WSIZ(D) ;GET # BYTES IN WINDOW
SUBI T2,(P2) ;GET # BYTES AVAILABLE
EXCH P1,P2 ;PUT THE BYTE REMAINDER IN P1
ADJBP P1,P2 ;UPDATE THE BYTE PNTR
MOVEI P2,(T2) ;GET BYTES AVAILABLE WHERE IT SHOULD BE
ADDM P2,BYTN(D) ;SET BYTE NUMBER TO AFTER THIS WINDOW
POPJ P,
> ;END IF20
IF10,<
%OBUF:
OSBUF:
%OSMAP: AOS T1,BLKN(D) ;INCR BLOCK #
IMULI T1,200 ;GET WORD # OF NEXT BLOCK
IMUL T1,BPW(D) ;AND GET BYTE #
MOVEM T1,BYTN(D) ;STORE FOR EOFN CALC
MOVE T2,CHAN(D) ;WRITE CURRENT BLOCK
HRRI T2,.FOOUT
MOVE T1,[1,,T2]
FILOP. T1,
$ECALL IOE,%ABORT ;REPORT ERROR AND DIE
POPJ P, ;DONE
ISBUF:
%ISMAP: AOS T1,BLKN(D) ;INCR BLOCK #
IMULI T1,200 ;GET WORD # OF NEXT BLOCK
IMUL T1,BPW(D) ;GET BYTE #
MOVEM T1,BYTN(D) ;SAVE FOR EOFN CALC
MOVE T2,CHAN(D) ;GET CHANNEL STUFF
HRRI T2,.FOINP ;READ NEXT BLOCK
MOVE T1,[1,,T2]
FILOP. T1,
PUSHJ P,EOFCHK
POPJ P,
EOFCHK: LOAD T2,INDX(D) ;GET DEV INDEX
CAIN T2,DI.TTY ;TERMINAL?
TRNN T1,IO.EOF ;YES. EOF?
JRST ERRCHK ;NO, NOTHING SPECIAL
MOVE T2,[1,,T3] ;SET UP FOR CLOSE
MOVEI T3,.FOCLS
HLL T3,CHAN(D)
FILOP. T2, ;CLEAR EOF BIT, LEAVE TTY OPEN
$ECALL IOE,%ABORT
ERRCHK: MOVX T0,D%END ;Get EOF flag
TRNE T1,IO.EOF ;EOF?
IORM T0,FLAGS(D) ;Yes, this file is ended
TRNE T1,IO.EOF ;EOF OFF?
TRNE T1,IO.ERR+IO.EOT ;NO, ANY REAL ERR BITS?
$ECALL IOE,%ABORT
POPJ P,
> ;IF10
SUBTTL TAPE POSITIONING
;Come here from MTOP% after the unit number has been checked.
;IO args have been set up in A.xxx
;A POPJ will return from the MTOP% call.
MTOP: SKIPL T1,@A.MTOP ;GET OPERATION CODE
CAILE T1,MOPMAX ;NEGATIVE OR TOO BIG?
$ECALL IMV,%ABORT ;ILLEGAL MTOP VALUE
XMOVEI T2,. ;Current section number in LH
HRR T2,MOPNAM(T1) ;Get global address of ASCIZ name
MOVEM T2,%IONAM ;SET STATEMENT NAME FOR ERROR MESSAGES
PUSHJ P,SETD ;SET UP D
PUSHJ P,OPNDDB ;OPEN DDB IF NECESSARY
MOVE T1,FLAGS(D) ;GET FLAGS
TXNE T1,D%RAN ;RANDOM FILE?
$ECALL POI,%ABORT ;FILE POSITIONING OPERATIONS ILLEGAL
MOVE T1,@A.MTOP ;Get back MTOP number
PUSHJ P,@MOPDSP(T1) ;GO DO OPERATION
PJRST %SETAV ;RETURN (possibly doing ERR=, etc.)
MOPNAM: [ASCIZ /REWIND/] ;(0)
[ASCIZ /UNLOAD/] ;(1)
[ASCIZ /BACKSPACE/] ;(2)
[ASCIZ /BACK FILE/] ;(3)
[ASCIZ /ENDFILE/] ;(4)
[ASCIZ /SKIP RECORD/] ;(5)
[0] ;(6)
[ASCIZ /SKIP FILE/] ;(7)
MOPMAX==.-MOPNAM
MOPDSP: IFIW MOPREW
IFIW MOPUNL
IFIW MOPBSR
IFIW MOPBSF
IFIW MOPEND
IFIW MOPSKR
IFIW %POPJ
IFIW MOPSKF
IF20,<
;REWIND
MOPREW:
MOVE T0,FLAGS(D)
TXNE T0,D%END ;EOF?
PUSHJ P,BAKEOF ;YES. CLEAR IT
SETZM CREC(D) ;CLEAR RECORD NUMBER
MOVX T0,D%END ;File is now not at end
ANDCAM T0,FLAGS(D)
LOAD T1,INDX(D) ;GET DEV INDEX
CAIN T1,DI.DSK ;DISK?
JRST DSKREW ;CAN DO
CAIN T1,DI.MTA ;TAPE?
JRST MTAREW ;CAN DO
POPJ P, ;ELSE NOP
DSKREW: MOVE T0,FLAGS(D) ;Get DDB flags for this file
TXNE T0,D%OUT ;WAS IT OPEN FOR OUTPUT?
PUSHJ P,%SETIN ;Yes. Switch to input
SETZM IPTR(D) ;PRETEND NO I/O DONE
SETZM ICNT(D) ;NO BYTES IN BUFFER
SETZM BYTN(D) ;SET CURRENT BYTE NUMBER TO 0
POPJ P, ;DONE
MTAREW: MOVE T1,FLAGS(D) ;Get DDB flags
TXNN T1,D%IN+D%OUT ;If not open,
JRST JSTREW ;Don't call %SETIN
PUSHJ P,%SETIN ;Get file opened for INPUT
SETZM IPTR(D) ;PRETEND NO I/O DONE
SETZM ICNT(D) ;NO BYTES IN BUFFER
MOVEI T2,.MOREW ;SET TO REWIND TAPE
JRST DOMTOP ;GO DO MTOPR
JSTREW: PUSHJ P,MTAOJF ;Open JFN, aborts if fails
MOVEI T2,.MOREW ;Get function
PUSHJ P,DOMTP1 ;Do it
PJRST MTACJF ;Close file, release JFN, return.
;Routine to create a JFN to be used for magtape operations
;Returns .+1 if ok, JFN in "RWJFN"
;The JFN is opened for input.
;If fails, goes to %ABORT.
MTAOJF: MOVE T1,[POINT 7,TMDEV] ;Get device name with ":"
MOVEI T2,DEV(D) ;From the DDB
HRLI T2,(POINT 7,)
MTAOJ1: ILDB T3,T2 ;Get a byte
JUMPE T3,MTAOJ2 ;Null, done
IDPB T3,T1 ;Store
JRST MTAOJ1 ;Loop until null found
MTAOJ2: MOVEI T3,":" ;Append a colon
IDPB T3,T1 ;Now have DEV: in "TMDEV"
;Do our own GTJFN.
MOVX T1,GJ%SHT
HRROI T2,TMDEV
GTJFN%
ERJMP E.SNH ;?Dev must exist: OPENX was done!
HRRZM T1,RWJFN ;Save JFN
;Have to OPENF the file to do a TAPOP.
MOVX T2,OF%RD ;Read ACCESS, nothing else.
OPENF% ;Get READ access to file
ERJMP MTARWO ;?OPENF failed, give error
POPJ P, ;OK, return
;Here if OPENF failed
MTARWO: MOVE T1,RWJFN ;Release JFN
RLJFN%
ERJMP .+1 ;?Too bad
$ECALL OPE,%ABORT ;Give JSYS error and abort program
SEGMENT DATA
TMDEV: BLOCK 20 ;Device name with ":"
RWJFN: BLOCK 1 ;Temp JFN used for REWIND, UNLOAD
SEGMENT CODE
;Routine to close and release JFN gotten by MTAOJF
MTACJF: MOVE T1,RWJFN ;Get saved JFN
CLOSF%
$ECALL IJE,%ABORT ;?CLOSF failed, abort program
POPJ P, ;All worked, return
;BACKSPACE
MOPBSR: SKIPE FUMXD(D) ;MIXED-MODE FILE?
$ECALL CDF,%ABORT ;YES. CAN'T DETERMINE FORM=
PUSHJ P,%SETIN ;Switch to input if necessary
SKIPG CREC(D) ;ARE WE AT BEG OF FILE?
POPJ P, ;YES. CAN'T GO BACKWARDS
SOS CREC(D) ;NO. DECR RECORD COUNT
MOVE T0,FLAGS(D)
TXNE T0,D%END ;FILE AT END?
JRST BAKEOF ;YES. JUST BACK OVER IT
SKIPN IPTR(D) ;ANY I/O DONE YET?
POPJ P, ;NO. CAN'T BACKSPACE
LOAD T0,FORM(D) ;GET FORM=
CAIN T0,FM.UNF ;UNFORMATTED?
JRST UNFBSR ;YES.
SKIPE P3,FRSIZB(D) ;FIXED-LENGTH RECORDS?
JRST BFCOM ;YES. JOIN COMMON CODE
BSRVAR: PUSHJ P,FBTST ;FIND CURRENT EOL
HRRZ T1,IPTR(D)
CAMGE T1,WADR(D) ;BEG OF WINDOW?
POPJ P, ;BACKSPACED TO BEG OF FILE
FBSLP: AOS ICNT(D) ;INCR COUNT
MOVNI T1,1 ;BACK 1 CHAR
ADJBP T1,IPTR(D) ;GET NEW PNTR
MOVEM T1,IPTR(D) ;SAVE IT BACK
FBTST: HRRZ T1,IPTR(D) ;GET ADDR PART OF PNTR
CAMGE T1,WADR(D) ;BEG OF WINDOW?
PUSHJ P,SUBP1X ;YES. GET PREVIOUS ONE
HRRZ T1,IPTR(D)
CAMGE T1,WADR(D) ;STILL BEG OF WINDOW?
POPJ P, ;BACKSPACED TO BEG OF FILE
LDB T1,IPTR(D) ;GET BYTE
CAIL T1,12 ;LF, VT, FF?
CAILE T1,14
JRST FBSLP ;NO
POPJ P,
SUBP1X: LOAD T1,INDX(D) ;GET DEV INDEX
CAIN T1,DI.MTA ;TAPE?
JRST MTABSA ;YES
MOVE P1,IPTR(D) ;GET CURRENT PNTR
SUBI P1,1 ;BACK UP 1 WORD
PUSHJ P,%PTOF ;GET BYTE NUMBER OF THAT BYTE
JUMPLE P1,%POPJ ;SHOULD NEVER BE NEGATIVE IN FILE
MOVEM P1,BYTN(D) ;STORE FOR MAPPING
PUSHJ P,%ISMAP ;MAP IT BACK AGAIN
AOS IPTR(D) ;INCR THE POINTER
MOVN T1,BPW(D) ;AND DECR THE COUNT
ADDM T1,ICNT(D)
POPJ P,
MTABSA: MOVEI T2,.MOBKR ;BACKSPACE RECORD
PUSHJ P,DOMTOP ;BACK UP TO BEGINNING OF THIS RECORD
PJRST BAKMTA ;BACK 1 MORE, READ IT
UNFBSR: LOAD T0,MODE(D) ;GET DATA MODE
CAIE T0,MD.IMG ;BINARY?
JRST BINBSR ;YES. GO THERE
;IMAGE MODE. GET RECORDSIZE IN BYTES, GO TO COMMON CODE
SKIPN P3,URSIZB(D) ;RECORDSIZE SPECIFIED?
$ECALL CBI,%ABORT ;CAN'T BACKSPACE IF NO RECSIZ
JRST BFCOM ;JOIN COMMON CODE
BINBSR: HRRZ T1,IPTR(D) ;GET ADDR IN CURRENT PNTR
CAMGE T1,WADR(D) ;AT BEG OF WINDOW?
PUSHJ P,SUBP1X ;YES. MOVE BACK TO PREVIOUS WORD
HRRZ P3,IPTR(D) ;GET LOCAL ADDR
MOVE P3,(P3) ;GET END LSCW
TLZ P3,777000 ;GET LENGTH IN WORDS
IMUL P3,BPW(D) ;GET # BYTES IN RECORD
;NOW WE CALCULATE THE NUMBER OF BYTES TO THE CURRENT BYTE POINTER IN THIS
;BUFFER. COMPARE IT WITH THE RECORDSIZE. IF BACKSPACE WILL STILL BE IN
;THIS BUFFER, WE CAN JUST DO AN ADJBP AND MODIFY THE COUNT. OTHERWISE
;WE HAVE TO REMAP (DISK) OR BACKSPACE ITERATIVELY (MTA).
BFCOM: HRRZ T3,IPTR(D) ;GET CURRENT ADDR
SUB T3,WADR(D) ;GET OFFSET FROM BEG
ADDI T3,1 ;ADD THE CURRENT WORD
IMUL T3,BPW(D) ;GET BYTE OFFSET
HLLZ T1,IPTR(D) ;GET POINTER PART
MUL T1,BPW(D) ;GET # BYTES LEFT IN CURRENT WORD
SUBI T3,(T1) ;CALC REAL BYTE OFFSET
CAIGE T3,(P3) ;BACKSPACE WITHIN THIS WINDOW?
JRST COMBAK ;NO. MAP DISK OR LOOP MAGTAPE
ADDM P3,ICNT(D) ;UPDATE COUNT
MOVNI P3,(P3) ;GET NEG BYTE DIFF
ADJBP P3,IPTR(D) ;UPDATE PNTR
MOVEM P3,IPTR(D) ;SAVE IT
POPJ P,
COMBAK: LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.DSK ;DISK?
JRST COMMTA ;NO. MAGTAPE
MOVE P1,IPTR(D) ;GET CURRENT POINTER AGAIN
PUSHJ P,%PTOF ;CALC FILE POINTER
SUBI P1,(P3) ;CALC DESIRED FILE POINTER
MOVEM P1,BYTN(D) ;SAVE FOR MAPPING
PJRST %ISMAP ;MAP IT
COMMTA: SUBI P3,(T3) ;REDUCE # BYTES TO BACKSPACE
MOVEI T2,.MOBKR ;BACKSPACE TO BEG OF THIS BLOCK
PUSHJ P,DOMTOP
PUSHJ P,BAKMTA ;BACKSPACE TO PREV BLOCK, READ IT
CAIGE T3,(P3) ;BACKSPACE WITHIN THIS BLOCK?
JRST COMMTA ;NO. TRY AGAIN
ADDM P3,ICNT(D) ;YES. ADJUST COUNT
MOVNI P3,(P3) ;AND POINTER
ADJBP P3,IPTR(D)
MOVEM P3,IPTR(D) ;SAVE UPDATED POINTER
POPJ P,
BAKMTA: MOVEI T2,.MOBKR
PUSHJ P,DOMTOP ;BACK UP TO BEGINNING OF PREV RECORD
SKIPE B36FLG(D) ;OPENED IN 36-BIT MODE?
JRST BACKU ;YES. USE A DIFFERENT PNTR FOR SINR
LOAD T1,IJFN(D) ;READ THE RECORD
MOVE T2,WADR(D) ;POINT TO BUFFER
SUBI T2,1 ;POINT TO LAST BYTE IN PREV WORD
HXL T2,BYTPT(D)
MOVN T3,WSIZ(D) ;GET LENGTH OF WINDOW
SINR% ;READ BLOCK
ERCAL EOFCHK ;ERROR, GO TYPE MESSAGE
ADD T3,WSIZ(D) ;RETURN # BYTES IN T3
MOVEM T2,IPTR(D) ;SAVE PNTR TO LAST BYTE
SETZM ICNT(D) ;WITH COUNT=0
POPJ P,
BACKU: LOAD T1,IJFN(D) ;READ THE RECORD
MOVE T2,WADR(D) ;POINT TO BUFFER
HRLI T2,(POINT 36) ;GET BINARY BYTE POINTER
MOVN T3,WSIZ(D)
IDIV T3,BPW(D) ;GET # WORDS
SINR%
ERCAL EOFCHK ;ERROR, GO TYPE MESSAGE
IMULI T3,(T4) ;GET NEG # BYTES LEFT IN BUFFER
ADD T3,WSIZ(D) ;RETURN # BYTES IN BUFFER IN T3
HXL T2,BYTPT(D) ;WORD-ALIGN BYTE PNTR
MOVEM T2,IPTR(D) ;SAVE IT
SETZM ICNT(D) ;CLEAR COUNT
POPJ P,
BAKEOF: MOVX T0,D%END ;Clear EOF bit
ANDCAM T0,FLAGS(D)
SETZM ICNT(D) ;CLEAR BYTE COUNT
LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.MTA ;MAGTAPE?
POPJ P, ;NO
PUSHJ P,%CLSOP ;CLOSE, OPEN FILE
MOVEI T2,.MOBKR ;BACK OVER THE EOF MARK
PUSHJ P,DOMTOP
SKIPG CREC(D) ;ANY RECORDS BEHIND IT?
POPJ P, ;NO. NULL FILE
JRST BAKMTA ;YES. BACKSPACE, READ PREVIOUS BLOCK
;ROUTINES TO CONVERT BETWEEN FILE ADDRESSES AND PROCESS ADDRESSES
;
;%PTOF - CONVERT PROCESS ADDRESS TO FILE ADDRESS
;ARGS: P1 = ADDRESS, MUST BE IN THE MEMORY MAPPED TO THE FILE OPEN
; ON THE DDB POINTED TO BY D
;RETURN: P1 = CORRESPONDING BYTE NUMBER IN THE FILE
%PTOF:: JUMPE P1,%POPJ ;ADDRESS=0 MEANS FILE PAGE 0
MOVEI T1,(P1) ;GET ADDR ONLY
SUB T1,WADR(D) ;GET WORD OFFSET WITHIN WINDOW
IMUL T1,BPW(D) ;GET OFFSET IN BYTES
HLLZ T2,P1 ;GET THE LEFT HALF OF THE BP
MUL T2,BPW(D) ;GET # BYTES LEFT
ADD T1,BPW(D) ;ADD THE CURRENT WORD
SUBI T1,(T2) ;MINUS # CHARS LEFT
ADD T1,BYTN(D) ;ADD FILE OFFSET OF NEXT WINDOW
SUB T1,WSIZ(D) ;CALC FILE OFFSET
MOVE P1,T1 ;RETURN IN P1
POPJ P,
;UNLOAD
MOPUNL: LOAD T1,INDX(D) ;GET DEV INDEX
CAIE T1,DI.MTA ;TAPE?
JRST MOPREW ;NO, UNLOAD IS REWIND
SETZM CREC(D) ;CLEAR RECORD COUNT
MOVX T0,D%END ;File is now not at end
ANDCAM T0,FLAGS(D)
MOVE T1,FLAGS(D) ;Get DDB flags
TXNN T1,D%IN+D%OUT ;If not opened yet,
JRST JSTUNL ;Don't call "SETIN"
PUSHJ P,%SETIN ;Get file opened for input.
MOVEI T2,.MORUL ;SET FOR UNLOAD OPR
JRST DOMTOP ;GO DO IT
JSTUNL: PUSHJ P,MTAOJF ;Get a JFN with no filename
MOVEI T2,.MORUL ;UNLOAD it
PUSHJ P,DOMTP1
PJRST MTACJF ;Close, release JFN and return
;TOPS-20 BACKFILE
MOPBSF: LOAD T1,INDX(D) ;GET DEV INDEX
CAIE T1,DI.MTA ;TAPE?
POPJ P, ;NO, BACKFILE IS NOP
PUSHJ P,%SETIN ;Make sure we're open for input
PUSHJ P,ENDOUT ;SETUP PROPERLY
SETZM CREC(D) ;CLEAR RECORD COUNT
MOVX T0,D%END ;File is now not at end
ANDCAM T0,FLAGS(D)
MOVEI T2,.MOBKF ;SET FOR BACKSPACE FILE
PUSHJ P,DOMTOP ;GO DO IT
MOVEI T2,.MOBKF ;AND A 2ND TIME
PUSHJ P,DOMTOP
LOAD T1,IJFN(D) ;GET JFN
GDSTS% ;GET STATUS
TXNN T2,MT%BOT ;UNLESS BEG TAPE
PUSHJ P,FORWF
PJRST %CLSOP ;MAKE SURE NO STUPID EOF STATUS
;END FILE
MOPEND: AOS CREC(D) ;INCR REC #
LOAD T1,INDX(D) ;GET DEV INDEX
CAIN T1,DI.DSK ;DISK?
JRST DSKEND ;YES
CAIE T1,DI.MTA ;TAPE?
POPJ P, ;NO. ENDFILE IS A NOP
PUSHJ P,%SETOUT ;Set to output
PUSHJ P,%LSTBF ;OUTPUT LAST BUFFER, IF ANY
PUSHJ P,%CLSOP ;CLOSE FILE, OPEN FOR INPUT AGAIN
ENDOUT: SETZM IPTR(D) ;CLEAR THE PNTR/COUNT
SETZM ICNT(D)
MOVE T1,FLAGS(D)
TXO T1,D%IN+D%END ;WE ARE OPEN FOR INPUT, AT EOF
TXZ T1,D%OUT ;NO LONGER DOING OUTPUT
MOVEM T1,FLAGS(D)
POPJ P,
DSKEND: PUSHJ P,%SETOUT ;SET TO OUTPUT
PUSHJ P,%SETIN ;AND THEN TO INPUT AGAIN
MOVX T1,D%END+D%MOD ;AT EOF
IORM T1,FLAGS(D)
POPJ P, ;DONE
;TOPS-20 SKIP RECORD
MOPSKR: SKIPE FUMXD(D) ;MIXED-MODE FILE?
$ECALL CDF,%ABORT ;YES. CAN'T DETERMINE FORM=
PUSHJ P,%SETIN ;Switch to input
LOAD T0,FORM(D) ;GET FORM=
CAIE T0,FM.FORM ;FORMATTED?
JRST UNFSKP ;NO. UNFORMATTED SKIP
PJRST %IREC ;YES. JUST READ A RECORD
;SKIP FILE
MOPSKF: LOAD T1,INDX(D) ;GET DEV INDEX
CAIE T1,DI.MTA ;TAPE?
POPJ P, ;NO, SKIP IS NOP
MOVE T0,FLAGS(D) ;GET FLAGS
TXNN T0,D%IN+D%OUT ;FILE OPEN?
JRST JSTSKF ;NO. JUST SKIP A FILE
PUSHJ P,%SETIN ;Make sure file is open for input
PUSHJ P,ENDOUT ;SETUP PROPERLY
SETZM CREC(D) ;CLEAR RECORD COUNT
MOVX T0,D%END ;Clear EOF bit
ANDCAM T0,FLAGS(D)
MOVEI T2,.MOFWF ;SET FOR SKIP FILE
PUSHJ P,DOMTOP ;BUT IF WE WERE, DON'T GO ANYWHERE
PJRST %CLSOP ;MAKE SURE NO STUPID EOF BIT LEFT ON
JSTSKF: PUSHJ P,MTAOJF ;GET A JFN, OPEN MTA
MOVEI T2,.MOFWF ;DO A SKIP FILE MTOPR
PUSHJ P,DOMTP1
PJRST MTACJF ;GO CLOSE FILE, RELEASE JFN, LEAVE
FORWF: MOVEI T2,.MOFWF ;SKIP FILE
;DOMTOP - Routine to do the MTOP specified in T2. (does appropriate
; WAIT's etc.)
DOMTOP: LOAD T1,IJFN(D) ;GET JFN
;Enter at DOMTP1 if you want to use the JFN in T1.
DOMTP1: PUSH P,T2 ;SAVE THE OPERATION TO DO
MOVEI T2,.MONOP ;DO A WAIT
MTOPR%
ERJMP MTOPER
POP P,T2 ;GET THE OPERATION
MTOPR% ;DO OPERATION
ERJMP MTOPER
MOVEI T2,.MONOP ;AND DO A WAIT
MTOPR%
ERJMP MTOPER
POPJ P, ;DONE
MTOPER: ;IOERR (ILM,23,,?,$J,,%POPJ)
$ECALL ILM,%ABORT
> ;IF20
IF10,<
MOPREW: SETZM CREC(D) ;CLEAR RECORD COUNT
SETZM BLKN(D) ;AND BLOCK #
MOVX T0,D%END ;Clear EOF bit
ANDCAM T0,FLAGS(D)
LOAD T1,DVTYP(D) ;GET DEVICE INDEX
CAIN T1,.TYDTA ;DECTAPE?
JRST DTAREW ;YES
CAIN T1,.TYDSK ;DISK?
JRST DSKREW ;Yes
CAIN T1,.TYMTA ;Magtape?
JRST MTAREW ;Yes
POPJ P, ;OTHERWISE IT'S A NOP
.FOMTP==30
DTAREW: MOVE T1,FLAGS(D) ;Get DDB flags
TXNN T1,D%IN+D%OUT ;Is the DECTAPE open?
JRST RWDEVO ;Yes, don't use filename
PUSHJ P,%SETIN ;OPEN for input.
SETZM BLKN(D) ;CLEAR BLOCK NUMBER
MOVE T2,CHAN(D) ;LH= chan #
HRRI T2,.FOMTP ;MTAPE FILOP
MOVX T3,MTREW. ;REWIND
MOVE T1,[2,,T2]
FILOP. T1,
$ECALL IOE,%ABORT
POPJ P,
DSKREW: MOVE T1,FLAGS(D) ;Is file really OPEN?
TXNE T1,D%IN+D%OUT
PUSHJ P,CLSOPN ;Yes, CLOSE the file, open for input
POPJ P, ;Return
MTAREW: MOVE T1,FLAGS(D) ;Get flags
TXNN T1,D%IN+D%OUT ;Is file really OPEN
JRST RWDEVO ;No
PUSHJ P,CLSOPN ;CLOSE THE FILE, OPEN FOR INPUT
MOVEI T2,.TFREW ;Go do REWIND
PJRST DOMTOP
;Here to REWIND a non-directory device that is not opened yet.
; Can't use FILOP.'s because you need a filename for them.
RWDEVO: PUSHJ P,OPDEVO ;Open the device only
MOVE T1,ASCHN ;Get channel #
LSH T1,^D23 ;Shift to ac field
IOR T1,[MTREW.] ;Make instruction
XCT T1 ;** REWIND the device **
PJRST CLDEVO ;Close device and return
;Routine to OPEN the device only, (on a low channel).
; FILOP. is not done, because no file can be specified.
;The assigned channel is stored in ASCHN.
;Returns .+1 or takes ERR= or goes to %ABORT (if errors)
OPDEVO: SETZ T1, ;Get a free channel
PUSHJ P,%ALCHF ;Get a channel
$ECALL NFC,%ABORT ;?Too many OPEN units
MOVEM T1,ASCHN ;Save it
LSH T1,^D23 ;Shift into AC position
IOR T1,[OPEN T2] ;Get instruction to XCT
MOVEI T2,.IODMP ;Set dump mode
SETZ T4, ;No buffers
MOVE T3,DEV(D) ;Get device
XCT T1 ;** OPEN the device **
JRST OPDVFL ;?Failed
POPJ P, ;OK, return
;The OPEN UUO failed. Either "No such device"
;or "Assigned to another job".
OPDVFL: MOVE T1,DEV(D) ;See if this device exists
DEVTYP T1,
JRST OPDVNS ;?no such device
JUMPE T1,OPDVNS ;Or if 0 returned.
SKIPA T1,[ERDAJ%] ;"Device allocated to another job"
OPDVNS: MOVEI T1,ERNSD% ;"No such device"
$ECALL OPN,%ABORT ;Give error, abort if no ERR=
SEGMENT DATA
ASCHN: BLOCK 1 ;Assigned channel for non-FILOP. I/O
SEGMENT CODE
;Routine to CLOSE the device OPEN'ed by OPDEVO.
;Returns .+1 always
CLDEVO: MOVE T1,ASCHN ;Get assigned channel #
LSH T1,^D23 ;Shift into ac position
IOR T1,[RELEAS 0] ;Get a RELEASE instruction
XCT T1 ;Do it
MOVE T1,ASCHN ;Get channel #
PUSHJ P,%DECHF ;Deallocate it
$SNH ;?Not assigned, "can't happen"
POPJ P, ;Ok, return
;Still IF10
MOPBSR: SKIPE FUMXD(D) ;MIXED-MODE FILE?
$ECALL CDF,%ABORT ;YES. CAN'T DETERMINE FORM=
PUSHJ P,%SETIN ;Get file open for input
LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.DSK ;DISK?
CAIN T1,DI.MTA ;OR MAGTAPE?
JRST BSROK ;YES
POPJ P, ;NO. BSR IS NOP
BSROK: SKIPG BLKN(D) ;HAVE WE READ ANYTHING?
POPJ P, ;NO. BACKSPACE IS A NOP
SKIPG CREC(D) ;BEG OF FILE?
POPJ P, ;YES. CAN'T GO BACKWARDS
SOS CREC(D) ;NO. DECR RECORD COUNT
MOVE T0,FLAGS(D)
TXNE T0,D%END ;ARE WE AT EOF?
JRST BAKEOF ;YES. BACK UP AND GET PREV BLK
LOAD T1,MODE(D) ;GET FILE MODE
CAIN T1,MD.DMP ;DUMP MODE?
JRST BSRDMP ;YES. VERY SPECIAL
CAIN T1,MD.BIN ;IS IT BINARY?
JRST BSRBIN ;YES
CAIE T1,MD.ASC ;IS IT ASCII?
CAIN T1,MD.ASL
JRST BSRASC ;YES. GO LOOK BACKWARDS FOR LF
SKIPE URSIZW(D) ;NO. FIXED-LENGTH RECORDS?
JRST IMGFIX ;YES
$ECALL CBI,%ABORT ;NO. ERROR
BSRASC: SKIPE FRSIZB(D) ;FIXED-LENGTH RECORDS?
JRST ASCFIX ;YES. EASY TREATMENT
PUSHJ P,BACKUP ;BACK UP TO LF
HRRZ T4,IBCB(D) ;GET BUFFER ADDR
HRRZ T1,IPTR(D) ;GET ADDR OF PNTR
CAIGE T1,2(T4) ;AT BEG OF BUFFER?
POPJ P,
BACK1: MOVNI T1,1 ;DECR POINTER
ADJBP T1,IPTR(D)
MOVEM T1,IPTR(D) ;SAVE UPDATED POINTER
AOS ICNT(D) ;INCR COUNT
BACKUP: HRRZ T4,IBCB(D) ;GET BUFFER ADDR
HRRZ T1,IPTR(D) ;GET ADDR OF PNTR
CAIL T1,2(T4) ;AT BEG OF BUFFER?
JRST BACKOK ;NO
PUSHJ P,PRVBUF ;YES. GET ANOTHER
POPJ P, ;BEG OF FILE
HRRZ T4,IBCB(D) ;GET BUFFER ADDRESS
HRRZ T1,IPTR(D) ;CHECK IF STILL AT BEG OF BUFFER
CAIGE T1,2(T4) ;IS IT?
POPJ P, ;YES. AT BEG OF FILE
BACKOK: LDB T1,IPTR(D) ;GET CHAR
CAIG T1,14 ;EOL CHAR?
CAIGE T1,12
JRST BACK1 ;NO
POPJ P, ;YES. WE'RE DONE
%BAKEF:
BAKEOF: SOS BLKN(D) ;DECR BLOCK FOR THE EOF
%ISET: PUSHJ P,CLSOPN ;CLEAR THE EOF STATUS
LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIN T1,DI.DSK ;DISK?
JRST DSKEOF ;YES. GO DO USETI
CAIE T1,DI.MTA ;MAGTAPE?
POPJ P, ;NO. CAN'T DO ANYTHING ELSE
MOVEI T2,.TFBSB ;YES. BACKSPACE A FILEMARK
PUSHJ P,DOMTOP
LOAD T1,MODE(D) ;GET DATA MODE
CAIE T1,MD.DMP ;DUMP?
SKIPG BLKN(D) ;NO. ANY DATA?
POPJ P, ;LEAVE IF NO DATA OR DUMP MODE
MOVEI T2,.TFBSB ;BACK OVER THE RECORD WE WANT
PUSHJ P,DOMTOP
JRST COMEOF ;JOIN COMMON CODE
DSKEOF: MOVE T2,FBLK(D) ;GET CHANNEL STUFF
HRRI T2,.FOUSI ;DO USETI
SKIPG T3,BLKN(D) ;TO CURRENT BLOCK
POPJ P, ;LEAVE IF NULL FILE
MOVE T1,[2,,T2]
FILOP. T1,
$ECALL IOE,%ABORT
LOAD T1,MODE(D) ;GET DATA MODE
CAIN T1,MD.DMP ;DUMP?
POPJ P, ;YES. DON'T READ ANYTHING
COMEOF: MOVE T2,FBLK(D) ;GET CHANNEL STUFF
HRRI T2,.FOINP ;READ THE BLOCK
MOVE T1,[1,,T2]
FILOP. T1,
$ECALL IOE,%ABORT ;Should not fail with "EOF"
DMOVE T1,IPTR(D) ;GET PNTR/COUNT
HXL T1,BYTPT(D) ;GET PROPER BP (MON RETURNS 000700)
ADJBP T2,T1 ;POINT TO END OF DATA
MOVEM T2,IPTR(D) ;SAVE UPDATED BYTE POINTER
MOVE T1,ICNT(D) ;GET COUNT
SETZM ICNT(D) ;CLEAR COUNT
POPJ P,
BSRDMP: SKIPN T1,BLKN(D) ;GET BLOCK #
POPJ P, ;HAVEN'T DONE ANY INPUT YET
SOS BLKN(D) ;DECR THE BLOCK #
LOAD T2,INDX(D) ;GET DEVICE INDEX
CAIE T2,DI.DSK ;DISK?
JRST %BACKB ;NO. BACKSPACE AN MTA BLOCK
PJRST USET ;SET NEXT BLOCK TO CURRENT ONE
;HERE IF BINARY RECORD
BSRBIN: HRRZ T2,IBCB(D) ;GET BUFFER HEADER ADDR
HRRZ T1,IPTR(D) ;GET JUST ADDR IN PNTR
CAIGE T1,2(T2) ;BEFORE BUFFER?
JRST BBACK ;YES. MUST GET PREV BUFFER
MOVE P3,(T1) ;GET THE TYPE 3 LSCW
TLZ P3,777000 ;GET THE WORD COUNT OF LAST REC
IMUL P3,BPW(D) ;GET THE BYTE COUNT
JRST BCOM ;JOIN COMMON CODE
BBACK: PUSHJ P,PRVBUF ;GET THE PREVIOUS BUFFER
POPJ P, ;NON-SKIP MEANS BEGINNING OF FILE
HRRZ P3,IPTR(D) ;GET CURRENT ADDRESS
MOVE P3,(P3) ;GET TYPE 3 LSCW
TLZ P3,777000 ;GET WORD COUNT OF RECORD
IMUL P3,BPW(D) ;GET THE BYTE COUNT
JRST BCOM ;JOIN COMMON CODE
;HERE FOR ASCII OR IMAGE FIXED-LENGTH RECORDS
ASCFIX: MOVE P3,FRSIZB(D) ;GET RECORDSIZE IN BYTES
JRST BCOM ;JOIN COMMON CODE
IMGFIX: SKIPN P3,URSIZB(D) ;GET RECORDSIZE IN BYTES
$ECALL CBI,%ABORT ;CAN'T BACKSPACE IF NO RECSIZ
BCOM: HRRZ T2,IBCB(D) ;GET BUFFER HEADER ADDR
HRRZ T1,IPTR(D) ;GET CURRENT PNTR ADDR
SUBI T1,1(T2) ;GET OFFSET FROM 1 BEFORE BEG BUFFER
IMUL T1,BPW(D) ;GET BYTE OFFSET
HLLZ T2,IPTR(D) ;GET POINTER PART OF BP
MUL T2,BPW(D) ;GET # BYTES LEFT INTO T2
SUBI T1,(T2) ;CALC BYTE OFFSET FROM BEG BUFFER
JRST BPRVT ;GO TEST IF WITHIN BUFFER
BPREV: SUBI P3,(T1) ;UPDATE # BYTES TO BACKSPACE
PUSHJ P,PRVBUF ;GET PREV BUFFER
JRST BBEG ;AT BEG OF FILE
BPRVT: CAIGE T1,(P3) ;BACKSPACE WITHIN THIS BUFFER?
JRST BPREV ;NO. GO BACK SOME MORE
ADDM P3,ICNT(D) ;YES. UPDATE BYTE COUNT
MOVNI P3,(P3) ;GET NEGATIVE BYTE OFFSET
ADJBP P3,IPTR(D) ;UPDATE PNTR
MOVEM P3,IPTR(D) ;SAVE UPDATED PNTR
POPJ P,
BBEG: MOVE T1,IBCB(D) ;BEG FILE. GET ADDR OF BUFFER
MOVE T2,1(T1) ;GET # WORDS IN BUFFER
IMUL T2,BPW(D) ;GET # BYTES
MOVEM T2,ICNT(D) ;SAVE IT
ADDI T1,1 ;POINT TO BEG BUFFER-1
HXL T1,BYTPT(D) ;POINT TO BEG BUFFER
MOVEM T1,IPTR(D)
POPJ P,
;
;HERE WE MUST DIVERT THE POINTER TO THE PREVIOUS BLOCK
;AND RESET THE CHAR COUNT
PRVBUF: MOVE T1,BLKN(D) ;GET CURRENT BLOCK #
SOJLE T1,%POPJ ;CAN'T GO BACKWARDS
MOVEM T1,BLKN(D) ;SAVE IT BACK
PUSHJ P,REDBLK ;READ THE BLOCK
AOS (P) ;SKIP RETURN
POPJ P,
REDBLK: LOAD T2,INDX(D) ;GET DEVICE INDEX
CAIE T2,DI.MTA ;MAGTAPE?
JRST DSKRED ;NO. DISK
PUSHJ P,CLRBCB ;COUNT ACTIVES
PUSH P,P4 ;Get a spare perm ac
MOVEI P4,1(T1) ;Must back over current one too
MTABLP: MOVEI T2,.TFBSB ;SETUP FOR BACKSPACE
PUSHJ P,DOMTOP ;DO IT
SOJG P4,MTABLP ;BACKSPACE FOR ALL ACTIVES
POP P,P4 ;Restore P4
JRST GOREAD ;GO READ THE BLOCK
DSKRED: PUSHJ P,USET ;POINT TO PREVIOUS BLOCK
PUSHJ P,CLRBCB ;CLEAR THE USE BITS
GOREAD: MOVSI T1,(BF.VBR) ;TURN ON VIRGIN BUFFER RING
IORM T1,IBCB(D) ;IN THE BUFFER HEADER
MOVE T2,CHAN(D) ;GET CHANNEL
HRRI T2,.FOINP ;SETUP FOR INPUT
HRRZ T3,IBCB(D) ;POINT TO CURRENT BUFFER
MOVE T1,[2,,T2] ;2-WORD FILOP
FILOP. T1,
$ECALL IOE,%ABORT ;Should not fail with EOF
DMOVE T1,IPTR(D) ;GET PNTR/COUNT
HXL T1,BYTPT(D) ;GET PROPER BP (MON RETURNS 000700)
ADJBP T2,T1 ;POINT TO END OF DATA
MOVEM T2,IPTR(D) ;SAVE UPDATED BYTE POINTER
MOVE T1,ICNT(D) ;RETURN FULL COUNT IN T1
SETZM ICNT(D) ;AND CLEAR COUNT
POPJ P,
USET: MOVE T2,FBLK(D) ;GET FILOP WORD 0
HRRI T2,.FOUSI ;GET USETI CODE
MOVEI T3,(T1) ;GET THE BLOCK #
MOVE T1,[2,,T2] ;DO THE USETI
FILOP. T1,
$ECALL IOE,%ABORT
POPJ P,
;Routine to clear the "use" bits of all active buffers, and
; return how many there were in T1.
%CLRBC:
CLRBCB: SETZM ICNT(D) ;CLEAR BUFFER CONTROL BLOCK
HRLOI T1,7700 ;EXCEPT BYTE SIZE IN PNTR
ANDM T1,IPTR(D)
MOVE T2,CHAN(D) ;GET CHANNEL
HRRI T2,.FOWAT ;SETUP FOR WAIT
MOVE T1,[1,,T2] ;DO FILOP
FILOP. T1,
$ECALL IOE,%ABORT
SETZ T1, ;CLEAR ACTIVE BUFFER COUNT
HRRZ T3,IBCB(D) ;GET PNTR TO BUFFER
MOVEI T2,(T3) ;COPY IT
FNDUSE: MOVE T4,-1(T3) ;GET STATUS WORD
TLNE T4,40 ;TAPE EOF?
AOJA T1,USEDON ;YES. WE'RE DONE
MOVE T4,(T3) ;GET THE USE WORD
TLZE T4,(1B0) ;TURN OFF. WAS IT ON?
ADDI T1,1 ;YES. ADD TO ACTIVE COUNTER
MOVEM T4,(T3) ;PUT IT BACK
HRRZ T3,(T3) ;GET WHAT IT POINTS TO
CAIN T2,(T3) ;POINTING TO CURRENT BUFFER?
POPJ P, ;YES. WE'VE DONE IT
JRST FNDUSE ;AND TRY AGAIN
USEDON: HRLOI T4,377777 ;TURN OFF USE BIT JUST IN CASE
ANDM T4,(T3)
POPJ P,
;UNLOAD
MOPUNL: SETZM CREC(D) ;CLEAR RECORD COUNT
SETZM BLKN(D) ;CLEAR BLOCK #
MOVX T0,D%END ;File is now not at end
ANDCAM T0,FLAGS(D)
LOAD T1,DVTYP(D) ;GET DEVICE TYPE
CAIN T1,.TYDTA ;DECTAPE?
JRST DTAUNL ;YES
CAIN T1,.TYDSK ;DISK
JRST DSKUNL
CAIN T1,.TYMTA ;Or magtape
JRST MTAUNL
POPJ P, ;OTHERWISE IT'S A NOP
DSKUNL: SKIPN FBLK(D) ;IS FILE REALLY OPEN?
POPJ P, ;No, no-op.
PJRST CLSOPN ;Close file, leave OPEN for input.
MTAUNL: SKIPN FBLK(D) ;Is file really OPEN?
JRST ULDEVO ;No, just UNLOAD.
PUSHJ P,CLSOPN ;Close file, leav OPEN for input.
MOVEI T2,.TFUNL ;Setup for UNLOAD
JRST DOMTOP ;Go do it
DTAUNL: MOVE T1,FLAGS(D) ;Get DDB flags
TXNN T1,D%IN+D%OUT ;Is the DECTAPE open?
JRST ULDEVO ;Yes, don't use filename
PUSHJ P,%SETIN ;Open the dectape
MOVE T2,CHAN(D) ;LH= chann #
HRRI T2,.FOMTP ;MTAPE FILOP
MOVX T3,MTUNL. ;UNLOAD
MOVE T1,[2,,T2]
FILOP. T1,
$ECALL IOE,%ABORT
POPJ P,
;Here to UNLOAD a DECtape or magtape that is not opened yet.
; Can't use FILOP.'s because you need a filename for them.
ULDEVO: PUSHJ P,OPDEVO ;Open the device only
MOVE T1,ASCHN ;Get channel #
LSH T1,^D23 ;Shift to ac field
IOR T1,[MTUNL.] ;Make instruction
XCT T1 ;** UNLOAD the device **
PJRST CLDEVO ;Close device and return
;TOPS-10 BACKFILE
MOPBSF: LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.MTA ;MAGTAPE?
POPJ P, ;OTHERWISE IT'S A NOP
SETZM CREC(D) ;CLEAR RECORD COUNT
SETZM BLKN(D) ;CLEAR BLOCK #
MOVE T0,FLAGS(D)
TXNE T0,D%END+D%OUT ;EOF OR DOING OUTPUT?
PUSHJ P,CLREOF ;YES. CLOSE/OPEN THE FILE
MOVE T0,FLAGS(D)
TXNE T0,D%IN+D%OUT ;Is file not open?
PJRST DOBKFU ;OPEN already, just do the UUO's and return.
;The MTA is not open.
PUSHJ P,OPDEVO ;OPEN the device
PUSHJ P,DOBKFU ;Do the BACKFILE UUO's.
PJRST CLDEVO ;Close device and return.
;Subroutine to do the UUO's necessary for BACKFILE.
;The device is OPEN.
DOBKFU: PUSHJ P,BACKF ;NOW BACKSPACE OVER 2 EOF MARKS
PUSHJ P,BACKF
MOVEI T2,.TFSTS ;GET STATUS OF TAPE UNIT
PUSHJ P,DOMTOP
TXNE T1,TF.BOT ;BEG TAPE?
POPJ P, ;YES. JUST LEAVE
MOVEI T2,.TFFSF ;NO. MUST FORWARD AGAIN
PJRST DOMTOP
;TOPS-10 ENDFILE
MOPEND: AOS CREC(D) ;INCR REC #
PUSHJ P,%SETOUT ;Get file opened for output
LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.DSK ;DISK
CAIN T1,DI.MTA ;OR MTA
JRST .+2 ;YES
POPJ P, ;NO. END FILE IS NOP
PUSHJ P,CLSOPN ;CLOSE, THEN OPEN FOR INPUT
MOVX T0,D%END ;Set fake end if necessary
IORM T0,FLAGS(D)
AOS BLKN(D) ;SIMULATE READING THE EOF RECORD
POPJ P,
;TOPS-10 SKIP RECORD
MOPSKR: SKIPE FUMXD(D) ;MIXED-MODE FILE?
$ECALL CDF,%ABORT ;YES. CAN'T DETERMINE FORM=
PUSHJ P,%SETIN ;Set file open for input
LOAD T1,MODE(D)
CAIN T1,MD.DMP ;DUMP MODE?
JRST SKRDMP ;YES. VERY SPECIAL
LOAD T0,FORM(D) ;GET FORM=
CAIN T0,FM.UNF ;UNFORMATTED?
JRST UNFSKP ;YES. DO UNFORMATTED SKIP
JRST %IREC ;TO SKIP RECORD, JUST READ AND IGNORE
SKRDMP: AOS T3,BLKN(D) ;GET THE INCREMENTED BLOCK #
ADDI T3,1 ;WANT THE NEXT ONE
LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.DSK ;DISK?
JRST %SKIPB ;NO. SKIP AN MTA BLOCK
MOVE T2,FBLK(D) ;GET FILOP WORD 0
HRRI T2,.FOUSO ;GET USETO CODE
MOVE T1,[2,,T2] ;DO THE USETI
FILOP. T1,
PUSHJ P,%CLSER ;JUST RETURN ON EOF
POPJ P,
;TOPS-10 SKIP FILE
MOPSKF: LOAD T1,INDX(D) ;GET DEVICE INDEX
CAIE T1,DI.MTA ;MAGTAPE?
POPJ P, ;NO. SKF IS NOP
SETZM CREC(D) ;CLEAR RECORD COUNT
SETZM BLKN(D) ;CLEAR BLOCK #
MOVE T0,FLAGS(D)
TXNN T0,D%OUT ;WERE WE DOING OUTPUT?
JRST SKFIN ;NO
PUSHJ P,%SETIN ;Yes. Close file, open again
JRST SKFCOM
;File not opened for output.
SKFIN: MOVE T1,FLAGS(D)
TXNE T1,D%IN ;Is file OPEN?
JRST SKFINN ;Yes
PUSHJ P,OPDEVO ;OPEN device
MOVEI T2,.TFFSF ;Skip a file
PUSHJ P,DOMTOP
PJRST CLDEVO ;Close again, and return.
SKFINN: PUSHJ P,CLREOF ;Clear EOF for input file
SKFCOM: MOVEI T2,.TFFSF ;SKIP A FILE
JRST DOMTOP
%SKIPB: MOVEI T2,.TFFSB ;SKIP A BLOCK
PJRST DOMTOP
%BACKB: MOVEI T2,.TFBSB ;BACKSPACE BLOCK
PJRST DOMTOP
BACKF: MOVEI T2,.TFBSF ;BACKSPACE FILE
;DOMTOP - DOES MAGTAPE OP, RETURNS FLAGS IN T1
DOMTOP: MOVE T3,DEV(D) ;GET DEVICE NAME
MOVE T1,[2,,T2] ;DO TAPOP
TAPOP. T1,
$ECALL UTE,%ABORT ;?Unexpected TAPOP error $O,<T1>
MOVEI T2,.TFWAT ;THEN A WAIT
MOVE T4,[2,,T2]
TAPOP. T4,
$ECALL UTE,%ABORT
POPJ P,
CHKEF: MOVE T1,DEV(D) ;GET THE DEVICE NAME
MOVEM T1,MTCBLK ;SETUP FOR MTCHR
MOVE T1,[MTCLEN,,MTCBLK]
MTCHR. T1, ;GET CHARACTERISTICS
; IOERR (UME,,,?,Unexpected MTCHR error $O,<T1>,%ABORT)
$ECALL UME,%ABORT
SKIPE MTCBLK+.MTREC ;ANY RECS AFTER LAST EOF?
AOS (P) ;YES. NOT AT EOF THEN. SKIP RETURN
POPJ P,
;Clear EOF by CLOSE'ing and re-OPENing the file.
;If it was opened for output, leave it that way.
; If it was opened for input, leave it that way.
CLREOF: MOVE T2,FBLK(D) ;GET THE CHANNEL STUFF
HRRI T2,.FOREL ;CLOSE THE FILE
MOVE T1,[1,,T2]
FILOP. T1,
PUSHJ P,%CLSER
MOVSI T1,(FO.PRV+FO.ASC)
HLLM T1,FBLK(D) ;AND NOW REOPEN IT
MOVX T5,D%IN ;Get flag to set
MOVE T0,FLAGS(D) ;Get current DDB flags
TXNE T0,D%OUT ;If file is now OPEN for output,
MOVX T5,D%OUT ;Leave it that way
TXZ T0,D%IN+D%OUT+D%END ;Clear current flags
MOVEM T0,FLAGS(D) ;Store new DDB flags
PUSH P,T5 ;Save flags
PUSHJ P,%ST10B ;Setup .FOBRH, .FONBF
POP P,T5 ;Restore flags to set on OPEN
PUSHJ P,%CALOF ;Try re-opening the file
JRST %ABORT ;?Failed
POPJ P, ;Worked, return
SEGMENT DATA
BSRCNT: BLOCK 1 ;# WORDS FOR BACKSPACE
DMPNTR: BLOCK 1 ;DUMP LIST PNTR
DMPLST: BLOCK MAXARG+1 ;DUMP I/O LIST
BLOCK 1 ;THE ZERO WORD (JUST IN CASE)
MTCLEN==20
MTCBLK: BLOCK MTCLEN
SEGMENT CODE
;Routine to CLOSE and then re-OPEN a file for input.
;This will have the effect of clearing the EOF status if set.
CLSOPN: MOVE T1,FLAGS(D) ;GET FLAGS
TXNE T1,D%OUT ;FILE OPEN FOR OUTPUT?
PUSHJ P,%LSTBF ;YES. OUTPUT LAST BUFFER IF MTA
MOVE T2,FBLK(D) ;GET CHANNEL STUFF
HRRI T2,.FOCLS ;CLOSE THE FILE
MOVE T1,[1,,T2]
FILOP. T1,
PUSHJ P,%CLSER
MOVE T2,FBLK(D)
HRRI T2,.FOREL ;RELEASE THE CHANNEL
MOVE T1,[1,,T2]
FILOP. T1,
PUSHJ P,%CLSER
MOVE T1,[FO.PRV+FO.ASC+.FORED] ;OPEN IT FOR INPUT
MOVEM T1,FBLK(D)
SETZM LKPB+.RBALC(D) ;PREVENT TRUNCATION
MOVX T0,D%END+D%IO+D%OUT
ANDCAM T0,FLAGS(D) ;Clear flags
MOVX T5,D%IN ;Set this flag if OPEN works
PUSHJ P,%ST10B ;Setup .FOBRH, .FONBF
MOVX T5,D%IN ;Get flag again
PUSHJ P,%CALOF ;Try re-opening the file
JRST %ABORT ;Failed
POPJ P, ;Done, return
> ;IF10
SUBTTL FIND
;FIND STATEMENT
;
;POSITIONS A RANDOM-ACCESS DISK FILE SO THAT SUBSEQUENT I/O WILL TAKE LESS TIME
;IF SUFFICIENT COMPUTATION INTERVENES BETWEEN THE FIND AND THE I/O.
;
;10: IF THE UNIT IS IDLE, NOT TRANSFERRING DATA FOR THIS JOB OR ANY
; OTHER JOB, POSITIONS THE ACCESS ARMS TO THE CORRECT CYLINDER
;
;20: CAN'T BE DONE
;
;THIS STATEMENT IS ALMOST ENTIRELY WORTHLESS.
FENTRY (FIND)
PUSHJ P,%SAVAC ;SAVE USER'S ACS
PUSHJ P,%CPARG ;AND COPY ARGS
PUSHJ P,FMTCNV ;CONVERT OLD-STYLE ARG LIST
XMOVEI T1,[ASCIZ /FIND/] ;SET STATEMENT NAME FOR ERROR MESSAGES
MOVEM T1,%IONAM
PUSHJ P,IOARG ;MOVE ARGS TO A.XXX
PUSHJ P,CHKUNT ;Check unit number in range
; (Goes to ABORT% or ERR= if not).
PUSHJ P,SETD ;SET D AND U
PUSHJ P,%SETIN ;Get file opened for input
SKIPE A.REC ;MAKE SURE THERE IS A RECORD NUMBER
SKIPG T1,@A.REC ;GET RECORD NUMBER
$ECALL IRN,%ABORT ;ILLEGAL IF .LE. ZERO OR NO RECORD NUMBER
MOVEM T1,CREC(D) ;STORE IN DDB FOR ASSOCIATE VARIABLE
IF10,<
MOVE T3,FRSIZW(D) ;GET FORMATTED RECORD SIZE, WORDS
LOAD T1,FORM(D) ;GET FORM=
CAIE T1,FM.FORM ;FORMATTED?
MOVE T3,URSIZB(D) ;NO. GET UNFORMATTED RECORDSIZE IN WORDS
IMULI T3,-1(T1) ;GET WORD # IN FILE OF BEG OF REC
LSH T3,-7 ;CONVERT TO BLOCK NUMBER
ADDI T3,1
HLLZ T2,CHAN(D) ;GET CHANNEL NUMBER
HRRI T2,.FOSEK ;SET SEEK FUNCTION
MOVE T1,[2,,T2] ;POINT TO FILOP BLOCK
FILOP. T1, ;DO THE "SEEK" FILOP
$ECALL IOE,%ABORT
>;END IF10
PJRST %SETAV ;GO SET ASSOCIATE VARIABLE AND RETURN
SUBTTL IOLST
FENTRY (IOLST)
SKIPN %UDBAD ;DO WE HAVE A UDB?
POPJ P, ;NO. RETURN
PUSHJ P,%SAVIO ;SAVE ACS
PUSHJ P,%ISAVE ;AND COPY ARGS
MOVE U,%UDBAD ;RESTORE DDB ADDRESS
MOVE D,DDBAD(U)
IOLP: MOVE T1,(L) ;GET NEXT I/O LIST ENTRY
JUMPE T1,%POPJ ;0 IS END OF LIST, RETURN TO USER
LDB T2,[POINTR T1,ARGKWD] ;GET TYPE OF ENTRY
CAILE T2,6 ;IN RANGE?
SETZ T2, ;NO, ILLEGAL
XMOVEI T1,@(L) ;GET ADDR
XCT DATSUB(T2) ;GO TO APPROPRIATE DATA HANDLER
JRST IOLP ;CONTINUE UNTIL END OF LIST
;XCT TABLE
DATSUB: JRST ILL
PUSHJ P,FDATA
PUSHJ P,SLIST
PUSHJ P,ELIST
JRST FIN
PUSHJ P,SLST77
PUSHJ P,ELST77
ILL: ADDI L,1 ;INCR PAST ARG
JUMPE T1,%POPJ ;0 ARG IS OK
$ECALL IOL,%ABORT ;NON-ZERO ARG, ZERO KWD - BAD I/O LIST
FDATA: MOVEM T1,IO.ADR ;SAVE THE DATA ADDR
SETZM IO.INC ;ZERO INCREMENT
LDB T2,[POINTR ((L),ARGTYP)] ;GET DATATYPE
MOVEM T2,IO.TYP ;SAVE IT
MOVEI T3,1 ;1 ENTRY
MOVEM T3,IO.NUM
CAIN T2,TP%CHR ;CHARACTER?
JRST DCHAR ;YES. GO HANDLE SEPARATELY
MOVE T3,%SIZTB(T2) ;SET "ARRAY" LENGTH TO DATUM SIZE
MOVEM T3,IO.SIZ ;SAVE IT
AOJA L,@IOSUB(D) ;DO I/O
DCHAR: SKIPG T3,1(T1) ;GET VARIABLE SIZE
$ECALL ICE,%ABORT ;ZERO OR NEGATIVE SIZE (BAD SUBSTRING BOUNDS)
MOVEM T3,IO.SIZ ;SAVE IT
MOVE T1,(T1) ;GET PNTR
MOVEM T1,IO.ADR ;SAVE AS ADDR
AOJA L,@IOSUB(D) ;PROCESS SINGLE DATUM
;EXPLICIT FIN CALL
FENTRY (FIN)
SKIPN %UDBAD ;ANY UDB PNTR?
POPJ P, ;NO. JUST RETURN
PUSHJ P,%SAVIO ;SAVE USER'S ACS
MOVE U,%UDBAD
MOVE D,DDBAD(U)
FIN: SETZM IO.ADR ;NO DATA ADDR
JRST @IOSUB(D) ;GO FINISH UP
SLST77: SKIPLE T1,(T1) ;GET THE COUNT
JRST SLCOM ;JOIN COMMON CODE
MOVEI T1,(T1) ;NEG OR ZERO. TOSS AOBJN COUNT
JUMPG T1,SLCOM ;PRODUCED BY BUG IN COMPILER
;ZERO-TRIP SLIST. SKIP TO THE END OF THE LIST, WHICH IS
;ANY ZERO WORD (V5A) OR WORD WITH NON-ZERO KEYWORD.
ADDI L,1 ;POINT TO NEXT WORD
SLZTLP: MOVE T1,(L) ;GET IT
TXNE T1,ARGKWD ;NON-ZERO KEYWORD?
POPJ P, ;YES. END OF LIST
JUMPE T1,%POPJ ;ZERO IS OLD STYLE END
AOJA L,SLZTLP ;TRY AGAIN
POPJ P, ;AND LEAVE
SLIST: SKIPLE T1,(T1) ;GET THE COUNT
JRST SLCOM ;OK
MOVEI T1,(T1) ;NEG OR ZERO. TOSS AOBJN COUNT
JUMPG T1,SLCOM ;PRODUCED BY BUG IN COMPILER
MOVEI T1,1 ;ZERO-TRIP. USE 1-TRIP DO COUNT
SLCOM: MOVEM T1,IO.NUM ;STORE COUNT
MOVEM T1,LISCNT ;TWICE
HRRE T1,@1(L) ;GET INCREMENT
MOVEM T1,LINCR ;STORE INCREMENT
MOVEM T1,IO.INC ;ASSUME IT'S AN OK INCR
MOVE T1,3(L) ;GET WORD AFTER ARRAY ADDRESS
TXNN T1,ARGKWD ;IS IT ANOTHER ARRAY?
JUMPN T1,SLP0 ;YES, MUST DO ONE-BY-ONE THING
LDB T2,[POINTR (2(L),ARGTYP)] ;GET DATATYPE
MOVEM T2,IO.TYP ;SAVE IT
CAIN T2,TP%CHR ;CHARACTER?
JRST SLCHR ;YES
MOVE T1,%SIZTB(T2) ;GET ENTRY SIZE
MOVEM T1,IO.SIZ ;SAVE IT
IMULM T1,IO.INC ;MAKE INCR IN WORDS
XMOVEI T1,@2(L) ;GET ADDRESS
MOVEM T1,IO.ADR ;SAVE IT
MOVE T1,[ADD T1,IO.ADR] ;DO NOTHING WITH ZERO INCREMENT
MOVEM T1,IO.INS ;INSTRUCTION FOR FORMATTED I/O
ADDI L,3 ;SKIP OVER SLIST
PJRST @IOSUB(D) ;GO DO WHOLE ARRAY
SLCHR: XMOVEI T1,@2(L) ;GET ADDR OF DESCRIPTOR
SKIPG T2,1(T1) ;GET SIZE
$ECALL ICE,%ABORT ;ZERO OR NEGATIVE SIZE (BAD SUBSTRING BOUNDS)
MOVEM T2,IO.SIZ ;SAVE IT
IMULM T2,IO.INC ;MAKE INCR IN BYTES
MOVE T1,(T1) ;GET PNTR
MOVEM T1,IO.ADR ;SUBSTITUTE THE BYTE PNTR
MOVE T1,[ADJBP T1,IO.ADR] ;GET INCREMENT INST
MOVEM T1,IO.INS ;SAVE FOR FORMATTED I/O
ADDI L,3 ;SKIP OVER SLIST
PJRST @IOSUB(D) ;DO WHOLE ARRAY
SLP0: SETZM OFFS ;INITIALIZE OFFSET
ADDI L,2 ;POINT TO FIRST ARRAY ADDRESS
MOVEM L,SAVEL ;SAVE FOR LOOP THROUGH ALL ARRAYS
SLP1: MOVE L,SAVEL ;RESET L TO START OF SLIST
SLP: XMOVEI T1,@(L) ;GET AN ARRAY BASE ADDRESS
MOVE T3,(L)
TXNE T3,ARGKWD ;IS IT AN ARRAY ADDRESS?
JRST SLPE ;NO, END OF LOOP
JUMPE T3,SLPE ;ZERO IS END OF LIST, NOT VALID ADDRESS
LDB T2,[POINTR ((L),ARGTYP)] ;GET DATA TYPE OF ARRAY
MOVEM T2,IO.TYP ;SAVE IT
MOVE T3,OFFS ;GET OFFSET INTO ARRAY
CAIN T2,TP%CHR ;CHARACTER?
JRST SCHAR ;YES. DO IT SEPARATELY
MOVE T4,%SIZTB(T2) ;GET ELEMENT SIZE
MOVEM T4,IO.SIZ ;SAVE IT
IMULI T3,(T4) ;TURN ELEMENTS INTO WORDS
ADDI T1,(T3) ;ADD OFFSET TO BASE ADDRESS
JRST NSCHAR ;JOIN COMMON CODE
SCHAR: IMUL T3,1(T1) ;GET CHARACTER OFFSET
ADJBP T3,(T1) ;CREATE NEW PNTR
SKIPG T5,1(T1) ;GET VAR SIZE
$ECALL ICE,%ABORT ;ZERO OR NEGATIVE SIZE (BAD SUBSTRING BOUNDS)
MOVEM T5,IO.SIZ ;SAVE IT
MOVE T1,T3 ;GET PNTR INTO T1
NSCHAR: MOVEM T1,IO.ADR ;SAVE IT
MOVEI T3,1 ;SET # ELEMENTS TO 1
MOVEM T3,IO.NUM ;SAVE NUM ELEMENTS
SETZM IO.INC ;NO INCREMENT
PUSHJ P,@IOSUB(D) ;I/O THE ARRAY ELEMENT
AOJA L,SLP ;BUMP TO NEXT ARRAY ADDRESS, CONTINUE
SLPE: MOVE T1,LINCR ;GET INCREMENT
ADDM T1,OFFS ;BUMP OFFSET
SOSLE LISCNT ;DECREMENT COUNT
JRST SLP1 ;NOT YET ZERO, CONTINUE I/O
POPJ P, ;END OF SLIST
ELST77: SKIPLE T1,(T1) ;POSITIVE?
JRST ELNZ ;YES. JOIN COMMON CODE
MOVEI T1,(T1) ;NO. AVOID AOBJN COUNTS (BUG IN COMPILER)
JUMPG T1,ELNZ ;IF NON-ZERO, ASSUME POSITIVE COUNT
;ZERO-TRIP ELIST. JUST GO TO THE END, WHICH IS A ZERO WORD (V5A) OR
;WORD WITH A NON-ZERO KEYWORD (POST-V5A) FOR AN "INCREMENT" WORD.
ELZTLP: ADDI L,1 ;POINT TO INCR/ADDR PAIR
MOVE T1,(L) ;GET NEXT INCREMENT
TXNE T1,ARGKWD ;ANY KEYWORD?
POPJ P, ;YES. END OF LIST
JUMPE T1,%POPJ ;ZERO IS ALSO END OF LIST
AOJA L,ELZTLP ;TRY AGAIN
ELIST: SKIPLE T1,(T1) ;GET THE COUNT
JRST ELNZ ;OK
MOVEI T1,(T1) ;NEG OR ZERO. TOSS AOBJN COUNT
JUMPG T1,ELNZ ;PRODUCED BY BUG IN COMPILER
MOVEI T1,1 ;NO. 1-TRIP DO COUNT
ELNZ: MOVEM T1,LISCNT ;STORE COUNT
SETZM OFFS ;CLEAR OFFSET
ADDI L,1 ;POINT TO FIRST INCR/ADDR PAIR
MOVEM L,SAVEL ;SAVE FOR LOOP
ELP1: MOVE L,SAVEL ;RESET L
ELP: MOVE T1,@(L) ;GET AN INCREMENT
MOVE T3,(L) ;Get arg type bits
TXNE T3,ARGKWD ;CHECK FOR 0 KEYWORD FIELD
JRST ELPE ;NONZERO KEYWORD, END OF LOOP
JUMPE T3,ELPE ;ZERO IS END OF LIST
IMUL T1,OFFS ;GET OFFSET INTO ARRAY
LDB T2,[POINTR (1(L),ARGTYP)] ;GET ARG TYPE
MOVEM T2,IO.TYP ;SAVE IT
CAIE T2,TP%CHR ;CHARACTER?
JRST ELNC ;NO
XMOVEI T3,@1(L) ;GET ADDR OF DESCRIPTOR
SKIPG T2,1(T3) ;GET SIZE OF VARIABLE
$ECALL ICE,%ABORT ;ZERO OR NEGATIVE SIZE (BAD SUBSTRING BOUNDS)
MOVEM T2,IO.SIZ ;SAVE IT
IMUL T1,T2 ;GET OFFSET IN CHARACTERS
ADJBP T1,(T3) ;INCR BYTE POINTER
MOVEM T1,IO.ADR ;SAVE FOR I/O ROUTINE
JRST ECOM2 ;JOIN COMMON CODE
ELNC: MOVE T3,%SIZTB(T2) ;GET SIZE
MOVEM T3,IO.SIZ ;STORE IT
IMULI T1,(T3) ;MULTIPLY OFFSET BY ELEMENT SIZE
XMOVEI T3,@1(L) ;GET BASE ADDR
ADD T1,T3 ;ADD BASE ADDRESS TO OFFSET
MOVEM T1,IO.ADR ;SAVE FOR FORMATTED I/O
ECOM2: MOVEI T3,1 ;1 ENTRY
MOVEM T3,IO.NUM ;SAVE IT
SETZM IO.INC ;NO INCREMENT
PUSHJ P,@IOSUB(D) ;CALL I/O ROUTINE
ADDI L,2 ;BUMP TO NEXT INCREMENT/ADDRESS PAIR, CONTINUE
JRST ELP
ELPE: AOS OFFS ;INCREMENT OFFSET
SOSLE LISCNT ;DECREMENT COUNT
JRST ELP1 ;IF NOT YET ZERO, CONTINUE
POPJ P, ;END OF ELIST
SEGMENT DATA
LINCR: BLOCK 1 ;LOCAL INCREMENT
LISCNT: BLOCK 1 ;LOCAL COUNT
OFFS: BLOCK 1 ;LOCAL OFFSET
SAVEL: BLOCK 1 ;FOROTS ARG LIST PNTR LOCAL
FORPRG
END