1
0
mirror of https://github.com/PDP-10/its.git synced 2026-01-18 17:16:59 +00:00
PDP-10.its/src/syseng/file.591
Lars Brinkhoff 21896d5513 FILE - Chaosnet file server.
Also FILEI/FILEO.
2017-01-28 12:16:28 -08:00

8586 lines
221 KiB
Plaintext
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; -*- Mode: MIDAS -*-
;;; PDP-10 Chaosnet file server
;;; The source file for this program is kept in the following places
;;; on the MIT Chaosnet:
;;;
;;; AI: SYSENG; FILE >
;;; OZ:SS:<SYS.SYSTEM>FILE.MID
;;; SCRC:<CHAOS>FILE.MID
;;; SPEECH:SSY:<SYMBOLICS.CHAOS.SERVER>FILE.MID
;;; XX:SRC:<SYS.CHAOS>FILE.MID
;;;
;;; Send mail regarding this program to BUG-FILE at MIT-MC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ****
;; **** Changes that have been made:
;; ****
;;
;; Wednesday, 21 July 1982 --Gren
;;
;; If OPEN/DELETE/RENAME/CHANGE-PROPERTIES fails for access
;; violation, will try and CONNECT no password then try again
;; (see TRYCON - Must immediately proceed the failing JSYS).
;;
;; Conditionally assembling the Chaosnet-user-Capability checking,
;; since you could always just login as Anonymous, which has it.
;; See the $$CCUC
;;
;; Make a DIRECTORY command not return ?NO FILES MATCH THIS
;; SPECIFICATION as an error, but just give an empty list.
;;
;; Thursday, 29 July 1982 --Gren
;;
;; Make GTJFN errors "NO SUCH FILENAME", "NO SUCH FILE TYPE", and
;; "NO SUCH VERSION NUMBER" come back as FNF, but with the original
;; error text.
;;
;; If you get auto-CONNECTed to a directory, you will disconnect
;; back to your home dir after done with whatever file. See the
;; CNCTED flag.
;;
;; Noticed this was already done (taken from SHOULD list):
;;
;; "COMRFO should quote embedded spaces, colons, semicolons, ideally."
;;
;; Friday, 30 July 1982 --Gren
;;
;; Instead of hassling you about logging in all the time, you will
;; be logged in as ANONYMOUS if it all possible, and only pestered
;; if it can't be done. The LOGIN command then does the same as an
;; ACCESS
;;
;; Wednesday, 4 August 1982 --Gren
;;
;; Better yet than just logging you in as ANONYMOUS by default, it
;; tries to log you in as <Q.hostname>, and only if that fails does
;; it try ANONYMOUS. The <Q> directory also has files of the form
;; <Q>hostname.PASSWORD, which are analagous to ANONYMOUS.USERFILE.
;; Note that these <Q> dirs have NOT-TTY-LOGINABLE set, so only the
;; FILE server or other detached creatures can use them. You may
;; not explicitly give a N-T-L account with LOGIN - It is rejected.
;;
;; "COMPFN should become more robust." - I poked at it some. Looks
;; fine to me. Have yet to try it out tho.
;;
;; In COMPFN, FN2 now defaults to ">" (it was left 0 before, and
;; would choke).
;;
;; Saturday, 21 August 1982 --Gren
;; Make the DIRECTORY command default FN1 and FN2 to "*" so that
;; just saying "DIR" or "DIR FOO" will work.
;;
;;
;; Monday, 23 August 1982 --Gren
;; Added support for SUBMIT OPEN option, conditionalized with the
;; $$SUBM flag.
;;
;; Tuesday, 14 September 1982 --Gren
;; Response to an OPEN is now:
;; ... QFASLP<SP>CHARACTERP<SP>"writer"<NL> ...
;; where "writer" is the last writer of the file, in Lisp-READable
;; format, with "'s and /'s quoted.
;;
;; Thursday, 16 September 1982 --Gren
;; Fixed some of the COMPLETE code so it wouldn't blow up and
;; cause the program to die horribly, and merged in Moon's time
;; fixes.
;;
;; 9/20/82 Moon Merged Gren's version and the Symbolics version
;; into one
;;
;; Monday, 27 September 1982 --Gren
;; Added support for ENABLE-CAPABILITIES.
;;
;; 9/27/82 Moon Fix bugs in cross-device/directory rename checking on
;; ITS. Make CWD and ENABLE-CAPABILITIES work on Tenex
;; Fix command name comparison so CREATE-LINK is not
;; mis-parsed as CREATE-DIRECTORY
;; Add CREATE-LINK command for ITS
;;
;; Saturday, 2 October 1982 --Gren
;; Have ENABLE/DISABLE commands take arguments of which privs to
;; toggle (currently only WHEEL, OPERATOR, or ALL), and have both
;; return the state of your privs as <priv allowed> <T if enabled
;; else NIL> ...
;;
;; 10/9/82 Moon Send new standard 3-letter error codes
;; Put error messages in upper and lower case
;; Include disk free space in directory list, for Tenex
;; (TOPS-20 should probably do it the way ITS does)
;;
;; Sunday, 10 October 1982 --Gren
;; Scrapped assorted experimental OZ things, put in some 20X
;; directory space listing stuff.
;;
;; Tuesday, 12 October 1982 --Gren
;; Doing SETNMs now for clarity's sake, added NLI LispM suicide
;; timout code, and conditionalized logging of activity, for
;; debugging porpoises ($$LOG).
;;
;; Thursday, 14 October 1982 --Gren
;; TWENEX returns freespace for all structures in directory stream
;; as STRUCTURE1:free1 STRUCTURE2:free2 ...
;;
;; Friday, 15 October 1982 --Gren
;; Conditionized out suicide stuff for now, since there don't seem
;; to be any interrupt channels to do it on, and it's no solution
;; anyway. $$SUE
;;
;; 18 Oct 82 Moon
;; Made it work again for ITS
;; Added INHIBIT-LINKS option for OPEN (ignored by systems without links)
;; Made OPEN options 10 characters instead of 5
;; IFN 0'ed GTDAL in 20X directory header, commented why
;; Got upset stomach from reading code in mixed case
;; Fixed ITS error messages
;;
;; Tuesday, 19 October 1982 --Gren
;; Put back in fixed GTDAL, Meta-C'd entire buffer.
;;
;; 10/21/82 Moon
;; Fix IOC errors to send proper 3-letter code.
;; Fix ITS error messages which I broke on 18 Oct.
;; Remodularize the error-message code to be more host-independent
;;
;; 10/26/82 MT
;; For 20X rel 5: use FB%NDL instead of FB%UND, if it's defined.
;;
;; Thursday, 28 October 1982 --Gren
;; Get writes to a specific version of a file go through a scratch
;; file, so there is no chance of clobbering the old copy.
;;
;; Saturday, 30 October 1982 --Gren
;; Try to DWIM if you DIRECTORY a <dir> without the *'s.
;;
;; Monday, 1 November 1982 --Gren
;; Put the directory-listing stuff on a separate GTJFN routine
;; (COMGDJ - uses Long Form) to avoid that DWIM kludge.
;;
;; Tuesday, 9 November 1982 --Gren
;; Change all ERJMP JSYSER's to ERCAL JSYSER's and include the
;; address of JSYS error along with the error string. JSYSER
;; should only be called via ERCAL since it expects TOS to be
;; the PC and such. If you want to do like JRST JSYSER, JRST
;; to COMFER instead. [Inoperative!]
;;
;; Saturday, 13 November 1982 --Gren
;; Switch file-overwriting back to the old catch-OPNX27-error
;; scheme, make sure JFNs released when erroring, fix delete/
;; temporary-file dual usage of DATRFJ. Ran out of usable bits
;; in DATSTA LH!
;;
;; Monday, 15 November 1982 --Ian
;; Various bug fixes having to do with when to release leftover
;; JFNs (now only done at close time). Returning number-of-
;; LM-characters-received on a CLOSE reply. No more $$SUE.
;;
;; Tuesday, 16 November 1982 --Ian
;; Centralized most of the Closing/Releasing of JFNs at RELDJF
;; and RELRJF
;;
;; 11/17/82 Moon -- fixed bugs I noticed
;; $$LOG should not be on by default
;; NOTNEW was not always initialized before calling COMGJF/COMGJG
;; COMOPN needs to release any JFNs held even if ST.ACT is not set
;; TRYCON thought A was 1 and also broke ERCAL
;; RLJFN fails if the JFN is open, so try CLOSF and RLJFN both
;; Fix errors in TNX/ITS conditionalization, Tenex timebombs
;; Use BUG 3-letter code for all unexpected errors
;; Make SYSBUG bug-tracing message not be as mysterious to users
;;
;; 11/19/82 Moon
;; Fix TRYCON more.
;; Don't call RELDJF when not supposed to, at CNGERR
;;
;; 12/1/82 Moon
;; If closing in abort mode, set CZ%ABT to suppress generation-retention-count
;; Send an async mark if data packet discarded for any reason
;; Send OPEN reply only after all done, in case interrupt accidentally
;; left enabled, so data packets don't arrive early (especially
;; when transaction-logging is turned on, making COMSND slow)
;;
;; 12/4/82 Moon
;; Fix clobbering of error code introduced by centralized closing of JFNS
;;
;; (some time) Gren (I assume)
;; OZ INQUIR data base has user groups
;; Default version for directory to * when user is not a Lisp machine
;; (unfortunately this was done in such a way that it can only work on OZ)
;;
;; 12/29/82 Moon
;; Recognize BIN files
;; Remove timebombs put in by previous modification
;;
;; 1/5/83 Moon
;; Put more wheel/operator capability required 20X error codes into ERRTAB
;;
;; 2/15/83 Moon
;; Revise error reporting. Include octal PC for all file-system bugs.
;; Normal expected errors from the file system are reported
;; via PUSHJ P,FILERR (on 10X/20X this is ERCAL JSYSER or PUSHJ P,JSYSER
;; usually, however JSYSER and FILERR are the same).
;; For ITS, ERRCOD must have been set up (via .CALL error return value)
;; PUSHJ P,SYSBUG is used for unexpected errors from the file system.
;; In DEBUG mode, even non-bug error messages include the octal PC.
;; You can also patch the JRST at BUGPAT to a JFCL to get this.
;; Also fix commands that use IDX without initializing it.
;;
;; 5/18/83 Moon v.508
;; Probe opening allowed for files that are off-line on Twenex
;;
;; Monday, 23 May 1983 --Ian
;; Fix another case for directory-empty: GJFX19 (No such file type)
;; is what you get if you directory "*.BAR" and there are no matching
;; files.
;;
;; 5 June 1983 Moon
;; Tops-20 needs to access other structure in COMPLETE command
;;
;; Wednesday, 8 June 1983 CSTACY
;; Fix INQUIR kludges, use proper LSRTNS routines.
;;
;; 9 June 83 Moon v.514
;; ACCCHK in COMPLETE command for Tops-20
;;
;; 14 June 83 Moon v.515
;; Do ACCESS to foreign structures once, at login time, instead
;; of all over the place. This avoids the problem that there were
;; lots of places that forgot to call ACCCHK.
;;
;; 16 June 83 Moon v.516
;; Return truenames from RENAME command (not finished for ITS yet)
;;
;; 13 July 83 Moon v.519
;; Don't return bogus file dates from ITS files that have never
;; been referenced.
;; More ACCESS/CONNECT fixes for Twenex
;;
;; 19 July 1983, GZ, v.519
;; Process LOGICALS.CMD on login, under $$LNM switch (off except on OZ).
;;
;; 19 July 83 Moon v.520
;; Merge my changes and GZ's changes
;; EXPUNGE command ignored by ITS
;; DELETED open option ignored by ITS
;; HOMEDIR, FILE-SYSTEM-INFO commands
;; Directory of FOO > on ITS matches only files with all-numeric FN2
;;
;; 23 August 83 Ian / Moon v.524
;; Missing ERCAL after RCDIR in EXPUNGE command
;;
;; Sunday, 4 September 1983 --Ian (524)
;; COMPFN defaults FN2 to ">" if STARF2/ 0 else "*" (for the sake
;; of directory listings)
;;
;; 9/6/83 Moon v.526
;; New OPEN options: ESTIMATED-LENGTH, PROBE-DIRECTORY,
;; IF-EXISTS, IF-DOES-NOT-EXIST (except for rename and rename-and-delete)
;; For ITS, the latter two aren't implemented yet
;;
;; 9 September 1983 --Ian (527,531)
;; Fixed 20X EXPUNGE not to need filename and to handle
;; wildcarded directories; Fix EXPUNGE code which somehow
;; reverted to a non-working test version (11-Sep)
;;
;; 9/12/83 Moon
;; Put back kludges needed to make EXPUNGE work on Tenex
;;
;; 9/19/83 Marty v533
;; Turned on $$LNM for all Top-20 versions.
;;
;; 9/23/83 Moon v.534
;; SFUSX6 gives a CSP error (mainly of use for Tenex)
;; Undefined 10X/20X error codes don't give a blank error message!
;;
;; 3 October 1983 --Ian
;; OZ Inquire support.
;;
;; 10/21/83 Moon
;; Add IF-EXISTS TRUNCATE (sets file length but doesn't return disk pages!)
;; Replace DATDEL, DATRFJ, and ST.OVW with DATDSP, to implement
;; IF-EXISTS RENAME and IF-EXISTS RENAME-AND-DELETE
;; Don't send bogus months in dates (can exist in ITS dates sometimes)
;; Still can send bogus days, though, but I think that's okay for
;; the moment. Dates should really be transmitted as universal times.
;; IF-EXISTS, IF-DOES-NOT-EXIST still not implemented for ITS
;;
;; 10/27/83 Moon v.543
;; Merge SCRC and OZ versions
;; Fix typo in HOMEDIR command when no Inquir entry found
;;
;; 10/31/83 Moon v.545
;; Ian's changes of 3 October broke users not registered in INQUIR on OZ
;; Ian's changes since last assembled on ITS broke ITS assembly
;;
;; 11/28/83 Moon v.547
;; PROBE-DIRECTORY bugs: release JFN, return truename, work on TOPS-20
;;
;; 12/06/83 Marty v. 546 (v. 548)
;; Make Tops-20 abort all open connections upon logout.
;;
;; 12/13/83 Moon v.549
;; Code was all scrambled in EXPUNGE command somehow
;;
;; 12/21/83 Moon v.551
;; IF-EXISTS SUPERSEDE ignored on ITS since system 243.369 sends it
;; Real implementation of IF-EXISTS, IF-DOES-NOT-EXIST for ITS still not done
;;
;; 1/4/84 Moon v.555
;; PROPERTIES command
;;
;; 1/16/84 Moon v.556
;; Merge the following changes from UTexas
;;
;; 12/13/83 C.Dawson (UTexas) v. 10547
;; Fix lossage when number of structures on system is exactly
;; equal to monitor's STRN. In this case, the GETAB table will
;; NOT contain a structure named STRnnn, and this can't be checked
;; for loop termination.
;;
;; 12/13/83 B. Brown (UTexas) v. 20547
;; Set session remark to "CHAOS SERVER" at startup. Useful for
;; Exec's who discriminate among various flavors of detached jobs.
;;
;; 1/29/84 Moon v.557
;; Lisp machine has gotten more picky about only accepting well-formed
;; dates, so put in more checks for bogus dates in date printer.
;;
;; 2/21/84 Moon v.558
;; Allow superseding a Tops-20 offline or archived file
;;
;; 20 June 1984 --Ian
;; For OZ, make the session-remark "CHAOS SERVER hostname" so FINGER
;; can show it.
;;
;; Monday, 9 July 1984, CJL
;; For TWENEX, If the RETENA is nonzero, for opens that would normally
;; bomb out will "File is off-line", a file retrieval is automatically
;; run, and the open is retried. For OZ, RETENA is set to -1.
;; Someday I hope there will be some way to change the value of RETENA
;; so this feature can be enabled and disabled at runtime. Insrts also
;; to LIB: instead of SYSTEM:, on OZ
;;
;; 9/7/84 MMcM v.567
;; :CHARACTERS :DEFAULT re-OPENF should respect PRESERVE-DATES.
;; Anonymous and archive retrieval changes weren't properly conditionalized.
;; 19-Nov-84, GZ, v.568
;; Adopt to hakinq library changes (OZ only).
;; Enable self at PURIFY so can dump file.
;;
;; 31 January 1985 --Ian v.569
;; Set XUNAME on ITS to name logging in as, fixed accumulated
;; ITS-assembly problems.
;;
;; 23-Feb-85, GZ, v.570
;; Add FILE-BYTE-SIZE open option on TNX
;;
;; 4/8/85, Alan, v.571 (ITS)
;; Set HSNAME on ITS.
;;
;; 5/02/85, CStacy (apparently), v.572 (ITS)
;; God only knows what he did.
;;
;; 20-May-86, COLE, v.571 (20X) (renamed v.573 after the fact on OZ)
;; FILE now computes byte size even when not in binary mode
;;
;; 2-July-86, SRA, v.574
;; Make session remark hack work for XX, without all the host
;; table mapping crud fer gossake. Added XX conditional.
;; Make OZ and XX conditional IFNDEFs work in domainland.
;; Merge OZ, XX, AI versions together again.
;;
;; 5-Oct-86 JTW v.575
;; Set file byte size only on BINARY WRITE operations (undo 571,
;; really). Fix incompatability with Symbolics Rel-7 which wants
;; to set character files to 8-bit bytes.
;;
;; 8-Dec-86 GLR v.576
;; Make open for output return filelength if file is old
;; 8-Dec-86 GLR v.582
;; hack filepos to work for output files -- this has timing screws in it
;; 8-Dec-86 GLR v.586
;; increase NIMPUR -- so it compiles on ITS
;;
;; 12/19/86 Alan v.587 (ITS)
;; Fixed code in ITS directory creation that tried to assure that only
;; people with directories can create directories. I'll bet this is
;; what CStacy did in v.572.
;;
;; 6/2/88 Alan v.591 (20X)
;; Return .FBTP1 .FBSS1 .FBTP2 .FBSS2 file properties.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFNDEF ITS,[
IFE .OSMID-SIXBIT/ITS/,ITS==1
.ELSE ITS==0
];IFNDEF ITS
IFNDEF 10X,[
IFE .OSMID-SIXBIT/TENEX/,10X==1
.ELSE 10X==0
];IFNDEF 10X
IFNDEF 20X,[
IFE .OSMID-SIXBIT/TWENEX/,20X==1
.ELSE 20X==0
];IFNDEF 20X
IFNDEF TNX, TNX==1-ITS
IFN ITS, TITLE FILE JOB FOR ITS
IFN 20X, TITLE FILE JOB FOR TOPS-20
IFN 10X, TITLE FILE JOB FOR TENEX
IFE <<<SIXBIT/MIT-OZ/>-<.SITE >>*<<SIXBIT/OZ.AI./>-<.SITE >>>, OZ==1
.ELSE OZ==0
IFN OZ, PRINTX /(OZ's munched on version)
/
IFE <<<SIXBIT/MIT-XX/>-<.SITE >>*<<SIXBIT/XX.LCS/>-<.SITE >>>, XX==1
.ELSE XX==0
IFN XX, PRINTX /(XX'S slightly munched on version)
/
DEFINE INFORM A,B,C,D,E,F,G
PRINTX /A!B!C!D!E!F!G
/
TERMIN
DEFINE CONC A,B,C,D,E,F,G
A!B!C!D!E!F!G!TERMIN
IFN ITS,[
NIMPUR==2 ;Number of low impure pages (ran over by 1 word)
PURBEG==NIMPUR*2000
] ;END IFN ITS
IFN TNX,[
.DECSAV
NIMPUR==4 ;Number of low impure pages
PURBEG==NIMPUR*1000
JOBSYM=116 ;Pointer to symbol table, in our own core
NSYMPG==3 ;Number of pages left for symbol table
IFN OZ,[
NSYMPG==4 ;doesn't quite fit otherwise
IPAGE==400 ;map in inquire database here
];End OZ
];END IFN TNX
;AC definitions
F=0 ;FLAGS ET AL.
;;; AC's 1 thru 3 (and sometimes 4) are used for Tops-20 JSYS'
;;; On Tenex, the GETER JSYS will smash AC's 4-10 as well.
T=4 ;SUPER TEMPORARIES
TT=5
A=6 ;NOT SO SUPER TEMPORARIES, BUT FOR GENERAL USE
B=7
C=10
D=11
IDX=12 ;INDEX INTO TABLES POINTING TO FILE CURRENTLY BEING HACKED
; LOW ORDER BIT 0=INPUT, 1=OUTPUT
BP=13 ;POINTER INTO PACKET
BYTE=14 ;CURRENT BYTE BEING HACKED
FHN=15 ;CURRENT FILE HANDLE
BC=16 ;BYTE COUNT REMAINING IN CONTROL PACKET
P=17 ;PDL POINTER, OF COURSE (THIS BETTER BE 17 FOR TOPS-20)
IFN ITS,[
;Get CHAOS definitions
.INSRT SYSTEM;CHSDEF
] ;END IFN ITS
IFN 20X,[
LOC 140
IFE OZ\XX,[
.INSRT SYSTEM:CHSDEF
];NOT OZ\XX
IFN OZ\XX,[
.INSRT MID:CHSDEF
];OZ\XX
] ;END IFN 20X
IFN 10X,[
LOC 140
.INSRT FILDEF
] ;END IFN 10X
%CPMXW== 126. ;Note: we want max over ALL systems here ...
%CPMXC== 488.
;IFNDEF CHPMXW, CHPMXW==%CPMXW-%CPKDT
;IFNDEF CHPMXC, CHPMXC==%CPMXC
;; Flag bits
F.FHN==:1_0 ;IF SET THERE WAS A VALID FILE HANDLE IN THE CONTROL REQUEST
F.NWL==:1_1 ;COMEUS HAS SEEN A NEWLINE
F.PRB==:1_2 ;DOING A PROBE
F.QFP==:1_3 ;QFASLP
F.FN1==:1_4 ;Guess....
F.FN2==:1_5
F.DEV==:1_6
F.DIR==:1_7
IFN TNX,[
F.SPAC==:1_8 ;A space has been seen while building error code
F.NRJ==:1_9 ;Don't release JFN in CLOSIT
F.ENA==:1_10. ;Enable after login
] ;END IFN TNX
F.DEF==:1_11. ;:CHARACTERS :DEFAULT
IFN OZ,[
F.LSP==:1_12. ;Coming from a LispMachine
];OZ
F.PDR==:1_13. ;PROBE-DIRECTORY
;; Flag bits in LH(F) controlling file creation options for OPEN
F.CRE==:1_18. ;Create file if does not exist (for overwrite/append)
F.SUP==:1_19. ;Supersede even if ask for newest version
F.APP==:1_20. ;Append to file
F.OVW==:1_21. ;Overwrite file
F.NEW==:1_22. ;File must be new, error if already exists
F.REN==:1_23. ;Rename existing file
F.RND==:1_24. ;Rename and delete existing file
F.TRU==:1_25. ;Truncate existing file and overwrite
IFN ITS,[
DEFINE SYSCAL OP,ARGS
.CALL [SETZ ? SIXBIT /OP/ ? ARGS ((SETZ))]
TERMIN
;; I/O CHANNELS
UTILCH==0 ;UTILITY CHANNEL: PROBES, TTY
;;; The CHAOS channels must be contiguous
CTRLI==1 ;CONTROL CONNECTION INPUT
CTRLO==2 ;CONTROL CONNECTION OUTPUT
ERRCH==17 ;Error channel
;; REMAINING CHANNELS FOR USE FOR REAL I/O
;; GROUP 1:
;; 3, DATA CONNECTION IN. 4, DATA CONNECTION OUT
;; 11, INPUT FILE. 12, OUTPUT FILE
;; GROUP 2:
;; 5, DATA CONNECTION IN. 6, DATA CONNECTION OUT
;; 13, INPUT FILE. 14, OUTPUT FILE
;; GROUP 3:
;; 7, DATA CONNECTION IN. 10, DATA CONNECTION OUT
;; 15, INPUT FILE. 16, OUTPUT FILE
;; EXTRA ENTRY FOR PROBING
CHACHN: 3 ? 4 ? 5 ? 6 ? 7 ? 10 ? -1
CHALOW==:1
CHAHIG==:10
CHABIT: 10 ? 20 ? 40 ? 100 ? 200 ? 400
DATCHN: 11 ? 12 ? 13 ? 14 ? 15 ? 16 ? UTILCH
MAXIDX==6 ;NUMBER OF INFORMATION CHANNELS. N/2 INPUT, N/2 OUTPUT
;LOW ORDER BIT 0=INPUT, 1=OUTPUT
] ;END IFN ITS
IFN TNX,[
GDACC=<JSYS 331> ;Gotta add this to MIDAS's symbol table.
PRILE1: 0 ;Three locations for storage of old PC at interrupt time
PRILE2: 0
PRILE3: 0
LV1ACS: BLOCK 20 ;Room for the ACs
LV1SAC: 0 ;Routine to be JSR'ed to to save AC's at level 1
MOVEM 0,LV1ACS
MOVE 0,[1,,LV1ACS+1]
BLT 0,LV1ACS+17
MOVE 0,LV1ACS
JRST @LV1SAC
MAXIDX==16.
CHABIT: IRPS BITPOS,,[0,1,2,3,4,5,23,24,25,26,27,28,29,30,31,32,33]
1_<35.-BITPOS!.>
TERMIN
CHAICN: 0,,1
2,,3
4,,5
23.,,24.
25.,,26.
27.,,28.
29.,,30.
31.,,32.
33.,,33.
;; Channels 34. and 35. are reserved by monitor for toplevel job!
CHAJFN: BLOCK MAXIDX+1
] ;END IFN TNX
;;; Impure tables
;;; Per data-connection tables
DATFHN: BLOCK MAXIDX+1 ;File handle
DATSTA: BLOCK MAXIDX+1 ;Status
DATBYT: BLOCK MAXIDX+1 ;Byte-size
DATBPW: BLOCK MAXIDX+1 ;Bytes per word
DATBUF: BLOCK MAXIDX+1 ;Buffer
DATBPT: BLOCK MAXIDX+1 ;Buffer pointer
DATBCT: BLOCK MAXIDX+1 ;Buffer count
DATIOC: BLOCK MAXIDX+1 ;Storage over IOC errors
DATLEN: BLOCK MAXIDX+1 ;File bytes remaining (Text)
DATRCV: BLOCK MAXIDX+1 ;LM bytes received (Text)
DATSYA: BLOCK MAXIDX+1 ;Synch mark routine
DATSYN: BLOCK MAXIDX+1 ;Synch mark routine arg
DATLWD: BLOCK MAXIDX+1 ;Last word
DATICN: BLOCK MAXIDX+1 ;IOC error continuation address
IFN ITS,[
DATDEV: BLOCK MAXIDX+1 ;Device
DATFN1: BLOCK MAXIDX+1 ;First filename
DATFN2: BLOCK MAXIDX+1 ;Second filename
DATSNM: BLOCK MAXIDX+1 ;Sname (directory)
];ITS
IFN TNX,[
DATJFN: BLOCK MAXIDX+1 ;JFN
DATDSP: BLOCK MAXIDX+1 ;Disposition of file when closed
;RH is JFN of file being replaced
;LH is flag bits:
DD.SUP==:1 ;Supersede old file by renaming to JFN in RH
DD.REN==:2 ;Rename old file, then rename new file
DD.RND==:4 ;Same as DD.REN, but delete old file too
DD.ABT==:10 ;Close in abort mode, delete the new file
DD.OPN==:20 ;File in RH is open (to lock it), remember to close it
DATFBS: BLOCK MAXIDX+1 ;File byte size
];TNX
;Status contains:
ST%CLO==:0 ;Closed state (initial state)
ST%OPN==:1 ;Open state
ST%ASY==:2 ;Asynchronous marked state
ST%SYN==:3 ;Synchronous marked state
ST%EOF==:4 ;Eof state
ST.SYN==:(1_22) ;Synchronous mark (expected, on input; needed, on output)
ST.BIN==:(1_23) ;Binary mode
ST.UNC==:(1_24) ;The last asynchronous error is uncontinuable
ST.DEL==:(1_25) ;Deleted files are ok
IFN TNX,[
ST.TEM==:(1_26) ;Temporary file
] ;END IFN TNX
ST.OUT==:(1_27) ;COMGJF wants file for output
ST.RAW==:(1_30) ;Raw: no character translation whatsoever
ST.SUI==:(1_31) ;Super-image: don't treat rubouts specially
ST.DIR==:(1_32) ;This channel is in use for directory hackery
ST.ACT==:(1_43) ;This channel is active (sign bit!)
IFN TNX,[
ST.PON==:(1_33) ;COMGJF should do parse only
];TNX
ST.NOK==:(1_34) ;New file ok for completion, also used by COMPR4
ST.FST==:(1_35) ;Fast directory listing option
ST.ALD==:(1_36) ;Directories only listing option (ALL-DIRECTORIES)
ST.PDT==:(1_37) ;Don't update access dates, etc.
ST.SUB==:(1_40) ;Submit this file as batch
ST.PRO==:(1_40) ;Doing PROPERTIES rather than DIRECTORY (same as ST.SUB!!)
ST.INL==:(1_41) ;Inhibit links
IFN 20X,[
ST.RET==:(1_42) ;WE RETRIEVED THIS FILE
];20X
;Opcodes:
CO%SYN==:%CODAT+1 ;Synchronous mark
CO%ASY==:%CODAT+2 ;Asynchronous mark
CO%NOT==:%CODAT+3 ;Notification
CO%BDT==:%CODAT\100 ;Binary data
CO%TXT==:%CODAT ;Text opcode
CO%EOF==:%COEOF ;EOF opcode
%CLEND==400000
; Packets
CTLPKI: BLOCK %CPMXW ;control in
CTLPKO: BLOCK %CPMXW ;control out
REAPKT: BLOCK %CPMXW
WRIPKT: BLOCK %CPMXW
ASYPKT: BLOCK %CPMXW
;;; Random impure data
DEBUG: 0 ;-1 if debugging, +1 means dump ourselves if error (-20 only)
;Set to zero if you purify, unless you change that
CHPMXW: %CPMXW-%CPKDT ; Left as-is for ITS, but adjusted for TOPS-20
CHPMXC: %CPMXC
IFN TNX,[
IFE OZ\XX,[
IFNDEF $$SUBM, $$SUBM==1 ;Allowing people to SUBMIT files to us?
IFNDEF $$CCUC, $$CCUC==1 ;Check Chaosnet-User-Capability?
IFNDEF $$LOG, $$LOG==0 ;Write log files
IFNDEF $$LNM, $$LNM==0 ;Parse logical-name definitions file at login time
];Not OZ\XX
IFN OZ\XX,[
IFNDEF $$SUBM, $$SUBM==1
IFNDEF $$CCUC, $$CCUC==0
IFNDEF $$LOG, $$LOG==0
IFNDEF $$LNM, $$LNM==0
];OZ\XX
ANONUM: 0 ;ANONYMOUS's user#
IFN 20X,[
DEVDEG: 0 ;[UTexas] for saving device designator
STRNAM: BLOCK 5 ;For converting sixbit structures to ascii
CNCTED: 0 ;are you foreignly connected?
CONFNM: BLOCK 10. ;Made by JFNS (for trying to CONNECT)
RETENA: 0 ;AUTOMATIC FILE RETRIEVALS ENABLED?
$$LNM==1 ;Process LOGICALS.CMD on login?
];20X
IFNDEF .SFCHA,$$CCUC==0 ;Only if MIDAS knows about Chaos capability do we care
IFE 20X,$$CCUC==0 ;No chaos checking on 10X
IFE 20X,$$SUBM==0 ;Or batch (of QUASAR sort)
IF1,[
IFN $$SUBM, INFORM Ability to submit batch jobs included
IFN $$CCUC, INFORM Checking of chaosnet-user capability included
IFN $$LOG, INFORM Log-file writing included
IFN $$LNM, INFORM Reading of LOGICALS.CMD file included
];IF1
TMPFIL: BLOCK 20 ;Temporary filename, for overwriting.
DMPACS: BLOCK 20 ;Save ACs when we dump ourselves
OZ$LOG==OZ*$$LOG
];TNX
IFE OZ,OZ$LOG==0
PDLEN==170
PDL: -PDLEN,,.+1 ;Size carefully chosen to give 1K impure
BLOCK PDLEN
FHNOUT: BLOCK 1 ;WORD TO OUTPUT FILE HANDLE FROM
0
PTCVER: 0 ;Protocol version number
IFN ITS, MACNAM: 0 ;The machine we are on
CLODAT: 0 ;Temporary storage by CLOSE operation
CLOLEN: 0
ERRCOD: 0 ;Error code returned by .CALL OPEN
SYSBGF: 0 ;Flag set to force 3-letter code to BUG
ERRLEN==:100.
ERRBUF: BLOCK ERRLEN/5
IFN ITS, SSYDF2: 0 ;Temporary storage of old DF2 word
TRANID: 0 ;Transaction ID
0
PKTLOC: CTLPKO ;COMCTL (et al.) use this as packet address
USERID: 0 ;User ID, set by LOGIN. Must be non-zero to do OPEN's
DIRPDL: 0 ;Saved stack for unwinding directory output
IFN ITS,[
STARF2: 0 ;Non-0 want "*" for default FN2, else ">"
HSNAME: 0 ;User HSNAME, sets files' authors
DIRLCK: 0 ;Only one channel can use DIRBUF
WRITER: BLOCK 2
] ;END IFN ITS
IFN TNX,[
RESLEN==:200
RESBLK: BLOCK RESLEN/5
CTLJFN: 0
WILDIR: 0 ;Temporary for EXPFNM
NOTNEW: 0 ;Flag for COMGJF - No GJ%NEW, please (ran out
;of bits for doing this in DATSTA, foo)
;0 => ST.OUT => GF%FOU and GJ%NEW
;1 => no GJ%FOU
;-1 => GJ%OLD (ignore ST.OUT)
INQBLK:
GTJBLK: ;For long call GTJFN for completion
CRDBLK: ;Argument block for CRDIR
DIRINF: BLOCK 50 ;For GTDIR info (in LOGIN command) and GTFDB
JFNSTR: BLOCK 30. ;For building JFN's, 149 chars should be ok
INQBLL==.-INQBLK
USRNUM: BLOCK 1
UDRNUM: BLOCK 1 ;Your home dir#
CWDNUM: BLOCK 1 ;dir# you have explicitly connected to
DWNTIM: BLOCK 1
IFN 10X, BLOCK 1
TIMINF: BLOCK 1
SAVEBP: BLOCK 1
WRITER: BLOCK 40./5
JFNBLK: .GJDEF ;Can be changed to .GJALL later
.NULIO,,.NULIO
0 ;Connected structure
0 ;Connected directory
-1,,[Ascii /*/] ;Default FILENAME,
-1,,[Ascii /*/] ;EXTENSION,
0 ;Default protection,
0 ;and account.
0 ;Not used (.GJJFN)
IFN $$SUBM,[
.QOCQE==37
.QCFIL==10
.QCQUE==24
.OTBAT==4
QUTILB: .MURSP ;Get PID of...
.SPQSR ;QUASAR...
QSRPID: 0 ;<here>
MSendB: 0 ;Arg block for the SUBMIT MSEND
YerPID: 0 ;Your PID
0 ;QUASAR's PID
1000,,QSRPAG ;1 page from here (saved, then restored).
];$$SUBM
IFN $$LNM,[
strbsz==200.
strbuf: block strbsz/5
atmbuf: block strbsz/5
cmdblk: 0,,lnm10
0,,.nulio ;.CMIOJ
440700,,[0] ;.CMRTY - no prompt
440700,,strbuf ;.CMBFP
440700,,strbuf ;.CMPTR
strbsz ;.CMCNT
strbsz ;.CMINC
440700,,atmbuf ;.CMABP
strbsz ;.CMABC
0 ;.CMGJB
];$$LNM
IFN $$SUBM,[
QPBLK: 0,,.QOCQE ;Create Queue Entry
0 ? 0 ;Unused header words.
0 ;Unused flag word
2 ;Two arg blocks...
2,,.QCQUE ;[#1] 2-word block: QUE type is...
.OTBAT ;BATCH
0,,.QCFIL ;[#2] n word block... a filespec.
BLOCK 12.
];$$SUBM
IFN OZ\XX,[
KSITE: BLOCK 10. ;Your site, like /MIT-LISPM-12/
Remark: Block 20. ;Session remark, "CHAOS SERVER " + KSITE
HostN: 0 ;Host number... hoo summoned us?
]
IFN OZ,[
GOTINQ: 0 ;Non-0 if have Inquire mapped in.
INQADR: 0 ;Address of user's Inquire entry (or 0 if none)
TimeOn: 0 ;Suicide TIMER is on.
DownpT: 0 ;System is going down, and channel 33 is in use.
LispMf: 0 ;Non-0 if connected from a LispM
LogJFN: 0 ;JFN for hangers-on log
IFN $$LOG,[
TriJFN: 0 ;Trickle file JFN
Trikle: Block 20 ;Trickle filename
];$$LOG
];OZ
];END IFN TNX
IMPLOC==.
LOC PURBEG
;;; Pure tables
IFN ITS,[
CTLOUT: SETZ
SIXBIT /PKTIOT/
%CLIMM,,CTRLO
%CLIMM+%CLEND,,CTLPKO
CTLINP: SETZ
SIXBIT /PKTIOT/
%CLIMM,,CTRLI
%CLIMM+%CLEND,,CTLPKI
] ;END IFN ITS
IFN OZ,[ ;NETWRK is pure code
.INSRT MID:MACROS
HOSTSP==100 ;Map HOSTS2 at this page.
$$CHAOS==1 ;We only want chaosnet.
$$HSTMAP==1 ;Map/unmap file utils;
$$HOSTNM==1
$$SYMLOOK==1
NETWRK"E=IDX
IFN NETWRK"E-<D+1>, .ERR NETWRK wants E to be D+1
.INSRT MID:NETWRK
%%T==T ? %%TT==TT ;HAKINQ expects AC4 to be available
T=C ? TT=D ;and since T=4, it loses very badly.
$$MAP==1
$$READ==1
$$XLATE==1
$$NPNAME==1
.INSRT MID:HAKINQ
T=%%T ? TT=%%TT
];OZ
;;; Macros
DEFINE CERR CODE,TEXT
JSP D,COMERR
SKIPA
'!CODE,,[ASCIZ \F TEXT\]
TERMIN
DEFINE AERR CONTIN,CODE,TEXT
JSP D,ASYERR
JRST .+3
'!CODE,,[ASCIZ \F TEXT\]
CONTIN
TERMIN
DEFINE IOCERR ADR
JSP D,ICCERR
SKIPA
ADR
TERMIN
;;; Main program. Startup, initialization, control connection main loop
FILE:
IFN ITS,SETZB F,DIRLCK
IFN TNX,SETZ F,
MOVE P,PDL
IFN ITS,[
.SUSET [.ROPTION,,T]
TLO T,OPTINT\OPTOPC ;TURN ON NEW STYLE INTERRUPTS
.SUSET [.SOPTION,,T]
.SUSET [.SDF1,,[%PIDBG+%PIDWN]] ;DEFER SYS DOWN, SYS DEBUG
.SUSET [.SMASK,,[%PIIOC+%PIDBG+%PIDWN]] ;ENABLE INTERRUPTS
.CALL [ SETZ ;GET OUT MACHINE'S NAME
SIXBIT /SSTATU/
MOVEM A ? MOVEM B ? MOVEM T ? MOVEM T ? MOVEM T
SETZM MACNAM]
.LOSE %LSSYS
SKIPLE A ;GET INITIAL HIT OF DOWN/DEBUG INTERRUPTS
.SUSET [.SIPIRQC,,[%PIDWN]]
SKIPE B
.SUSET [.SIPIRQC,,[%PIDBG]]
.CALL [ SETZ ;ASSIGN CHAOSNET CONTROL CHANNELS
SIXBIT /CHAOSO/
%CLIMM,,CTRLI
%CLIMM,,CTRLO
%CLIMM,,5 ((SETZ))]
.LOGOUT 1,
MOVEI T,%COLSN ;LISTEN FOR OUR CONTACT NAME
DPB T,[CTLPKO+$CPKOP]
MOVE T,[.BYTE 8 ? "F ? "I ? "L ? "E]
MOVEM T,CTLPKO+%CPKDT
MOVEI T,4
DPB T,[CTLPKO+$CPKNB]
.CALL CTLOUT ;OUTPUT THE LISTEN
.LOSE %LSSYS
MOVEI T,30.*30. ;30. SEC TIMEOUT
SKIPGE DEBUG ;UNLESS DEBUGGING
HRLOI T,177777
.CALL [ SETZ ;WAIT FOR A RESPONSE OR TIMEOUT
SIXBIT /NETBLK/
%CLIMM,,CTRLO
%CLIMM,,%CSLSN
T
SETZM TT]
.LOSE %LSSYS
CAIE TT,%CSRFC ;RFC RECEIVED?
.VALUE
.CALL CTLINP ;READ RFC PACKET
.LOSE %LSSYS
LDB T,[CTLPKI+$CPKOP]
CAIE T,%CORFC
.VALUE
MOVE P,PDL
PUSHJ P,CHKPVR ;CHECK PROTOCOL VERSION NUMBER
.VALUE ;ALREADY WILL HAVE SENT CLS IF NO GOOD
MOVEI T,%COOPN ;SEND OPN BACK
DPB T,[CTLPKO+$CPKOP]
.CALL CTLOUT
.LOSE %LSSYS
SKIPGE DEBUG ;DEBUGGING?
JRST CTLLOP ;YES, SO DON'T TRY TO LOGIN
LDB T,[$CPKSA CTLPKI] ;GET SOURCE HOST ADDRESS
MOVE TT,[SIXBIT /000C00/] ;CONVERT HOST NUMBER TO SIXBIT
DPB T,[220300,,TT]
LSH T,-3
DPB T,[300300,,TT]
LSH T,-3
DPB T,[360300,,TT]
.SUSET [.RUIND,,T] ;INCORPORATE USER INDEX ALSO
DPB T,[000300,,TT]
LSH T,-3
DPB T,[060300,,TT]
LSH T,-3
DPB T,[170100,,TT] ;C77 + 1 = K00 TO AVOID DUPLICATIONS
MOVE T,TT ;SAVE COPY FOR XUNAME
MOVEI A,100(TT) ;DON'T LOOP FOREVER, ONLY 100 TIMES
CHALS1: CAIN A,(TT)
.VALUE ;I DON'T THINK THIS CAN HAPPEN, BUT IT DOES ANYWAY
.CALL [SETZ
SIXBIT /LOGIN/
TT ? [SIXBIT /CHAOS/] ? SETZ T]
AOJA TT,CHALS1 ;ERROR, PERHAPS NEED TO TRY OTHER UNAME
.SUSET [.SJNAME,,[SIXBIT /FILE/]]
.CALL [SETZ ? 'DETACH ? MOVEI %JSELF ? ANDI 3 ]
.LOSE %LSSYS ;MAKE SELF SYSTEM-DAEMON FOR FAST RESPONSE
CTLLOP: MOVE P,PDL ;IN CASE OF ERROR, RESTORE PDL
SETZ F, ;CLEAR FLAGS
.SUSET [.SDF1,,[0]] ;ALLOW SYS DOWN, SYS DEBUG INTERRUPTS NOW
.CALL CTLINP ;GET NEXT CONTROL PACKET, HANG IF NECESSARY
.LOSE %LSSYS
.SUSET [.SDF1,,[%PIDBG+%PIDWN]] ;DEFER THESE INTS WHILE PROCESSING
LDB T,[CTLPKI+$CPKOP]
CAIL T,%CODAT ;THIS A DATA PACKET?
JRST COMMAN ;YES, OK, GO DO A COMMAND FROM IT
CAIE T,%COEOF ;LISP MACHINE WANT TO CLOSE THE CONNECTION?
JRST CTLLOP ;HMMM, BAD PACKET, IGNORE IT FOR NOW
CTLERR:
CTLDON: .LOGOUT 1, ;Go away immediately, do not RENMWO any output files
] ;END IFN ITS
IFN TNX,[
RESET ;Reset the Universe
MOVEI 1,.FHSLF ;Setup our interrupt vector
MOVE 2,[LEVTAB,,CHNTAB]
SIR
MOVEI 1,.FHSLF ;Turn on interrupt system
EIR
MOVEI 1,.FHSLF ;Enable interesting interrupts
MOVE 2,[000747,,000004]
AIC
IFN 20X,[
MOVE 1,[SIXBIT /CHPMXT/] ; Get max packet size
SYSGT
TLNE 1,-1
JRST [ MOVE 1,[SIXBIT /LHOSTN/] ; Old flavor monitor
SYSGT
CAIE 1,54 ; XX ?
SKIPA 1,300 ; no - size is 300
MOVEI 1,488. ; yes - size is max
JRST .+1 ]
MOVEM 1,CHPMXC ; Set max # chars
LSH 1,-2
MOVEM 1,CHPMXW ; Set max # words
]
MOVE 1,[SIXBIT /FILE/]
IFN 10X,SETNM
IFN 20X,[
MOVE 2,1
SETSN
JFCL
IFE OZ\XX,[
SETO 1, ;THIS JOB
MOVEI 2,.SJSRM ;SET SESSION REMARK
HRROI 3,[ASCIZ /CHAOS SERVER/]
SETJB ;DO IT
ERJMP .+1 ;OR DON'T
];IFE OZ\XX
];20X
HRLZI 1,(GJ%SHT) ;Short GTJFN to get the control channel
HRROI 2,[ASCIZ \CHA:.FILE\]
GTJFN
ERCAL CTLDON
HRRZM 1,CTLJFN ;JFN for control channel
MOVE 2,[100000,,OF%RD\OF%WR]
OPENF ;Listen for connection
ERCAL CTLDON
MOVEI 2,.MOPKR
MOVEI 3,CTLPKI
MTOPR
ERCAL CTLDON
MOVE P,PDL
PUSHJ P,CHKPVR ;CHECK PROTOCOL VERSION NUMBER
JRST CTLDN0 ;ALREADY WILL HAVE SENT CLS IF NO GOOD
MOVE 1,CTLJFN
MOVEI 2,.MOOPN ;Accept the connection
MTOPR
ERCAL CTLDON
PUSHJ P,TIMIN1 ;Turn on timer interrupts
IFN OZ,[
SETOM RETENA ;CHEAP WAY TO ENABLE FILE RETRIEVALS
MOVEI A,HOSTSP
PUSHJ P,NETWRK"HSTMAP ;Map in HOSTS2 database
JRST CTLLOP ; oops
];IFN OZ
IFN OZ\XX,[
LDB B,[$CPKSA+CTLPKI] ;SOURCE ADDRESS
Movem B,HostN ;Save for later.
];IFN OZ\XX
IFN OZ,[
PUSHJ P,NETWRK"HSTSRC ;Look up name of who's knocking
JRST CTLLOO
HRRO 2,A ;-1,,(A) in AC2
HRROI 1,KSITE ;Get the host-name in KNAME
SETZ 3,
SOUT
];IFN OZ
IFN XX,{ ;There's a perfectly good jsys,
MOVEI 1,.CHNNS ;why map host tables?
HRROI 2,KSITE
MOVE 3,HostN
CHANM%
ERJMP [HRROI 1,KSITE ;Lookup failed, use octal number
MOVE 2,B
MOVEI 3,8
NOUT%
ERJMP .+1 ;this shouldn't ever fail
JRST .+1]
};IFN XX
IFN OZ\XX,[
HRROI 1,REMARK
HRROI 2,[ASCIZ "CHAOS SERVER "]
SETZ 3,
SOUT
HRROI 2,KSITE
SOUT
SETO 1, ;THIS JOB
MOVEI 2,.SJSRM ;SET SESSION REMARK
HRROI 3,REMARK
SETJB ;DO IT
ERJMP .+1 ;OR DON'T
];IFN OZ\XX
IFN OZ,[
HLRZ A,1(D) ;Address of system-name
ADD A,NETWRK"HSTADR
MOVE T,(A)
CAMN T,[ASCII /LISPM/]
JRST [ TRO F,F.LSP ;We are a LispMachine
MOVEI 1,.FHSLF
SETO 3,
EPCAP ;Enable!!
JRST CTLLOO ]
Movei 1,.GJALL ;Known not to be a Lisp machine, use * as default vers
Movem 1,JFNBLK+.GJGEN
IFN $$LOG,[
Setom LispMf
GJINF
Move T,3
Hrroi 1,Trikle
Hrroi 2,[Asciz "SS:<TRIKLE>"]
Setz 3,
SOUT
Hrroi 2,KSite
SOUT
; Hrroi 2,[Asciz "-JOB-"]
; SOUT
; Move 2,T
; Movei 3,10.
; NOUT
; Jfcl
Hrroi 2,[Asciz ".LOG"]
Setz 3,
SOUT
Movsi 1,(GJ%SHT\GJ%FOU)
Hrroi 2,Trikle
GTJFN
Jrst CTLLOO ;No biggie (if it fails)
Movem 1,TriJFN
Move 2,[70000,,OF%WR]
OPENF
Jrst [Move 1,TriJFN
RLJFN
Jfcl
Setzm TriJFN
Jrst CTLLOO]
Seto 2, ;Now
Setz 3,
ODTIM
Hrroi 2,[Asciz " Log started
"]
Setz 3,
SOUT
];$$LOG
CTLLOO: PUSHJ P,NETWRK"HSTUNMAP ;We don't need those pages anymore
];OZ
CTLLOP: MOVE P,PDL ;For safety, reset the world
SETZ F,
SETO A, ;Allow timer interrupts
EXCH A,TIMINF ;See if timer went off
SKIPE A
PUSHJ P,DWNCHK ;It did, do check now
MOVE 1,CTLJFN ;Wait for a control packet
MOVEI 2,.MOPKR
MOVEI 3,CTLPKI
MTOPR
ERCAL CTLERR ;Flush ourselves if any error
IFN OZ$LOG,[
Skipn 1,TriJFN
Jrst CTLLOR
Seto 2,
Setz 3,
ODTIM
Hrroi 2,[Asciz " <==
"] ? Setz 3,
SOUT
Skipe TimeOn ;Activity! Turn off pending
Jrst [Move 1,[.FHSLF,,.TIMAL] ;suicide interrupt (actually
TIMER ;turn them all off)
Setzm TimeOn
Jrst .+1]
CTLLOR:
];OZ$LOG
SETZM TIMINF ;No longer allow timer interrupts
LDB T,[CTLPKI+$CPKOP]
CAIL T,%CODAT ;THIS A DATA PACKET?
JRST COMMAN ;YES, OK, GO DO A COMMAND FROM IT
CAIE T,%COEOF ;LISP MACHINE WANT TO CLOSE THE CONNECTION?
JRST CTLLOP ;HMMM, BAD PACKET, IGNORE IT FOR NOW
PUSHJ P,CTLDON ;Does not return.
CTLDON: SKIPG DEBUG ;Dump ourselves
JRST CTLDN0
MOVEM 0,DMPACS
MOVE 0,[1,,DMPACS+1]
BLT 0,DMPACS+17
MOVE 1,[GJ%SHT+GJ%FOU+GJ%NEW]
IFN 20X,HRROI 2,[ASCIZ \PS:<CRASH>DEAD-FILEJOB.EXE\]
IFN 10X,HRROI 2,[ASCIZ \DSK:<CHAOS>DEAD-FILEJOB.SAV\]
GTJFN
JRST CTLDN0
HRLI 1,.FHSLF
MOVE 2,[777760,,20]
SAVE
CTLDN0:
IFN OZ$LOG,[
Skipn 1,TriJFN
Jrst ZZZ
Seto 2,
Setz 3,
ODTIM
Hrroi 2,[Asciz " Closing log file - EOF received"]
Setz 3,
SOUT
CLOSF
Jfcl
ZZZ:
];OZ$LOG
IFN 10X,[ ;Tenex LGOUT doesn't do this itself
MOVEI IDX,MAXIDX-1 ;Last output channel
CTLDN1: HRRZ 1,DATSTA(IDX)
JUMPE 1,CTLDN2 ;ST%CLO
MOVE 1,DATJFN(IDX)
HRLI 1,(CO%NRJ) ;Close file, but keep around JFN
CLOSF
ERJMP CTLDN2 ;Ain't much else we can do...
DELF ;Delete the file and release JFN
ERJMP CTLDN2
CTLDN2: SUBI IDX,2
JUMPGE IDX,CTLDN1
];IFN 10X
IFN 20X,[
MOVEI 1,.FHSLF
HRLI 1,(CZ%ABT+CZ%NUD) ;Abort all output operations +
; don't update disk copy of directory
CLZFF ; and close all files
ERJMP .+1 ;oh well, we tried.
];IFN 20X
MOVNI 1,1 ;-1 means log us out
SKIPL DEBUG ;If debugging, just stop, will die if top-level
LGOUT ;Bye-bye
HALTF
JRST .-1
CTLERR: MOVEI 1,.FHSLF
PUSHJ P,$GETER
PUSHJ P,CTLDON ;Punt if no err
MOVE 1,[441000,,CTLPKO+%CPKDT]
MOVSI 3,-%CPMXC
ERSTR
PUSHJ P,CTLDON
JFCL
CTLER1: SETZ BC,
IFN 10X,IDPB BC,1 ;Put in null at end
MOVE 1,[441000,,CTLPKO+%CPKDT]
ILDB 2,1
CAIE 2,0
AOJA BC,.-2 ;Get real size
MOVEI T,%COLOS ;Send LOS packet
DPB T,[$CPKOP+CTLPKO]
DPB BC,[$CPKNB+CTLPKO]
MOVE 1,CTLJFN
MOVEI 2,.MOPKS
MOVEI 3,CTLPKO
MTOPR
ERCAL CTLDON
PUSHJ P,CTLDON
] ;END IFN TNX
;;; Called c(D)+1 has code,,pointer-to-asciz-string
COMERR: MOVEI A,[ASCIZ \ERROR \] ;INDICATE AN ERROR TO THE REQUESTOR
PUSHJ P,COMCTL
HLLZ A,1(D) ;GET ERROR CODE
PUSHJ P,COMSXO
MOVEI BYTE,40
PUSHJ P,COMCHO
HRRZ A,1(D) ;NOW OUTPUT THE ERROR STRING
PUSHJ P,COMSTO
PUSHJ P,COMSND
JRST CTLLOP
MINPTC==0
MAXPTC==1
;;; Check protocol version number
CHKPVR: MOVE BP,[441000,,CTLPKI+%CPKDT]
LDB BC,[CTLPKI+$CPKNB]
PUSHJ P,COMRD5 ;SHOULD BE FILE
TDZA A,A
PUSHJ P,COMDCI ;GET NUMBER INTO A
MOVEM A,PTCVER
CAIL A,MINPTC
CAILE A,MAXPTC
SKIPA
JRST POPJ1
MOVEI A,[ASCIZ \PROTOCOL VERSION \]
PUSHJ P,COMCTL
MOVE A,PTCVER
PUSHJ P,COMDCO
MOVEI A,[ASCIZ \ NOT SUPPORTED\]
PUSHJ P,COMSTO
MOVEI T,%COCLS
JRST COMSN1
;;; Here to handle a command over the control connection
COMBAD: CERR BUG,[Illegal request format]
COMMAN:
IFN OZ$LOG,[
SKIPN TRIJFN
JRST XXX2
LDB A,[$CPKNB+CTLPKI] ;Byte-count
MOVE B,[441000,,CTLPKI+%CPKDT]
PUSHJ P,PKTPRT
XXX2:
];OZ$LOG
MOVE BP,[441000,,CTLPKI+%CPKDT]
LDB BC,[CTLPKI+$CPKNB]
PUSHJ P,COMRD5 ;Get transaction ID
JRST CTLLOP ;Error, ignore this request (what else?)
MOVEM A,TRANID
TRZ F,F.FHN ;NO FILE HANDLE SEEN YET
MOVEI B,5 ;MAXIMUM FILE-HANDLE SIZE
SETZ FHN,
MOVE A,[440700,,FHN] ;ACCUMULATE FILE HANDLE
COMFHL: SOJL BC,COMBAD ;BAD CONTROL PACKET: PROTOCOL VIOLATION
ILDB BYTE,BP ;GET THE NEXT CHARACTER
CAIN BYTE,40 ;SPACE TERMINATES FILE HANDLE
JRST COMMA1 ;KEEP PROCESSING
IDPB BYTE,A
SOJG B,COMFHL ;ONLY READ FIRST 5 CHARACTERS
PUSHJ P,COMEUS ;EAT UNTIL SPACE SEEN
JRST COMBAD ;NON-SKIP, HIT END OF PACKET OR NEWLINE, ERROR
COMMA1: JUMPE FHN,COMMA2 ;DON'T HAVE A FILE HANDLE AFTER ALL
TRO F,F.FHN
MOVEI IDX,MAXIDX-1 ;LOOP OVER ALL INDICIES
COMMA3: CAMN FHN,DATFHN(IDX) ;MATCH?
JRST COMMA2 ;YUP, LEAVE IDX IN IDX
SOJGE IDX,COMMA3
CERR BUG,[Unknown file handle]
COMMA2: PUSHJ P,COMR10 ;READ 10 CHARACTERS INTO A AND B
JFCL
JUMPE A,[CERR BUG,[Null command name]]
MOVSI T,-COMTAL ;AOBJN POINTER
COMCO1: CAMN A,COMTAB(T) ;MATCH?
CAME B,COMTAB+1(T)
AOJA T,COMCO2 ;NO, TRY NEXT
HRRZS T ;YES, RUN THE COMMAND
LSH T,-1
JRST @COMDSP(T)
COMCO2: AOBJN T,COMCO1
CERR UKC,[Unknown command]
;;; Command table
COMTAB: ASCII \DATA-CONNE\ ;DATA-CONNECTION
ASCII \UNDATA-CON\ ;UNDATA-CONNECTION
ASCII \OPEN\ ? 0 ;OPEN
ASCII \CLOSE\ ? 0 ;CLOSE
ASCII \FILEPOS\ ;FILEPOS
ASCII \DELETE\ ;DELETE
ASCII \RENAME\ ;RENAME
ASCII \CONTINUE\ ;CONTINUE
ASCII \SET-BYTE-S\ ;SET-BYTE-SIZE
ASCII \LOGIN\ ? 0 ;LOGIN
ASCII \DIRECTORY\ ;DIRECTORY
ASCII \COMPLETE\ ;COMPLETE
ASCII \CHANGE-PRO\ ;CHANGE-PROPERTIES
ASCII \CREATE-DIR\ ;CREATE-DIRECTORY
ASCII \EXPUNGE\ ;EXPUNGE
ASCII \HOMEDIR\ ;HOMEDIR
ASCII \FILE-SYSTE\ ;FILE-SYSTEM-INFO
ASCII \PROPERTIES\ ;PROPERTIES
IFN ITS,ASCII \CREATE-LIN\ ;CREATE-LINK
IFN TNX,[
ASCII \CWD\ ? 0 ;CHANGE WORKING DIRECTORY (CONNECT)
IFN 20X,ASCII \ACCESS\ ;ACCESS DIRECTORY
ASCII \ENABLE-CAP\ ;ENABLE-CAPABILITIES
ASCII \DISABLE-CA\ ;DISABLE-CAPABILITIES
];TNX
COMTAL==<.-COMTAB>/2
COMDSP: COMDCN
COMUDC
COMOPN
COMCLO
COMFIL
COMDEL
COMREN
COMCON
COMSBS
COMLOG
COMDIR
COMCPL
COMCNG
COMCRD
COMEXP
COMHOM
COMFSI
COMPRO
IFN ITS,COMCRL
IFN TNX,[
COMCWD
IFN 20X,COMACD
COMENA
COMDIS
];TNX
IFN .-COMDSP-COMTAL, .ERR COMDSP and COMTAB lengths disagree
;;; Subroutines
;Read the next token from the stream. Reads the first 5 bytes, and throws away the rest.
; Destroys T, TT, and BYTE; result in A. Tail recurses to COMEUS
COMR10: MOVEI T,10. ;ALLOW 10 CHARACTERS INTO A AND B
TDZA B,B
COMRD5: MOVEI T,5
TRZ F,F.NWL
SETZ A,
MOVE TT,[440700,,A] ;ACCUMULATE TOKEN IN A
COMR5A: SOJL BC,CPOPJ ;END OF PACKET, HAVE TOKEN
ILDB BYTE,BP ;GET THE NEXT CHARACTER
CAIN BYTE,215 ;NEWLINE TERMINATES
JRST COMEUN
CAIN BYTE,40 ;SPACE TERMINATES THE TOKEN
JRST COMEUR
IDPB BYTE,TT
SOJG T,COMR5A ;ONLY READ FIRST 5 CHARACTERS
; JRST COMEUS ;FALL INTO COMEUS
;Eats until end of stream, space, or newline seen
; Non-skip return if end of packet or newline seen, skip return if space seen
COMEUS: SOJL BC,COMEUP ;IF END OF STREAM, RETURN
ILDB BYTE,BP ;NEXT BYTE
COMEUA: CAIN BYTE,215 ;NEWLINE
JRST COMEUN
CAIE BYTE,40 ;SPACE
JRST COMEUS ;NOPE, KEEP GOING
COMEUR: AOS (P) ;SKIP RETURN
COMEUP: TRZA F,F.NWL
COMEUN: TRO F,F.NWL
CPOPJ: POPJ P,
;Single byte output
;Must preserve TT
COMCHO: CAML BC,CHPMXC
CERR BUG,[Too much information to fit in a packet]
IDPB BYTE,BP
AOJA BC,CPOPJ
;;; For TOPS-20, output from RESBLK, where lots of interesting things get returned
IFN TNX, COMRES: SKIPA A,[440700,,RESBLK]
;String out, string address in A, COMST0 if already byte pointer
COMSTO: HRLI A,440700 ;MAKE A A STRING POINTER
COMST0: ILDB BYTE,A ;GET NEXT CHARACTER
COMST1: JUMPE BYTE,CPOPJ ;TERMINATE ON NULL
XCT CHR2LM(BYTE) ;CONVERT TO LISP MACHINE CHARACTER SET
PUSHJ P,COMCHO ;NON-SKIP, JUST OUTPUT
JRST COMST0
JRST COMST0 ;IGNORE RUBOUT ESCAPE, SHOULDN'T HAPPEN HERE
MOVEI BYTE,115 ;POSSIBLY STRAY RETURN, OUTPUT M TO BE SAFE NOW
PUSHJ P,COMCHO
ILDB BYTE,A ;AND ABSORB FOLLOWING LINE FEED
CAIE A,12
JRST COMST1
MOVEI BYTE,215 ;CARRIAGE RETURN FOR CRLF
DPB BYTE,BP ;REPLACE M IN PACKET
JRST COMST0
;Decimal output, value in A, destroys A and B
COMDCO: JUMPL A,CPOPJ ;IGNORE NEGATIVE NUMBERS
PUSH P,[-1] ;FLAG BOTTOM OF STACK
COMDO0: IDIVI A,10.
PUSH P,B
JUMPN A,COMDO0
COMDO1: POP P,BYTE
JUMPL BYTE,CPOPJ ;DO UNTIL NO MORE DIGITS
ADDI BYTE,"0
PUSHJ P,COMCHO
JRST COMDO1
;Octal output, value in A, destroys A
COMOCO: PUSH P,[-1] ;FLAG BOTTOM OF STACK
COMOO0: PUSH P,A
ANDI A,7 ;SAVE BOTTOM DIGIT
EXCH A,(P)
LSH A,-3
JUMPN A,COMOO0
COMOO1: POP P,BYTE
JUMPL BYTE,CPOPJ ;DO UNTIL NO MORE DIGITS
ADDI BYTE,"0
PUSHJ P,COMCHO
JRST COMOO1
;Sixbit output, sixbit in A, destroys A and B. Quotes funny characters.
COMSXO: MOVE B,A
COMSO0: JUMPE B,CPOPJ ;TERMINATE WHEN NO MORE BYTES
SETZ A,
LSHC A,6 ;GET NEXT BYTE
JUMPE A,COMSOQ ;QUOTE LEADING SPACES
CAIE A,': ;AND : OR ;
CAIN A,';
JRST COMSOQ
COMSO1: MOVEI BYTE,40(A) ;MAKE ASCII
PUSHJ P,COMCHO ;OUTPUT THE BYTE
JRST COMSO0
COMSOQ: MOVEI BYTE,"
PUSHJ P,COMCHO
JRST COMSO1
;Output date/time from A
COMDTO: PUSH P,D
MOVEI D,COMCHO ;Output char in BYTE to command response
JRST COMDT0
DIRDTO: PUSH P,D
MOVEI D,DIRCHO ;Output char in BYTE to directory listing
COMDT0:
IFN TNX,[
;; Internal date/time in A -- convert to ITS format
MOVE 2,A
AOSN A ;If -1, then use 0
SETZ 2,
SETZ 4,
ODCNV ;Convert internal date/time to printable format
ERCAL SYSBUG
HRRZ A,4 ;Local time in seconds
LSH A,1 ;Number of half-seconds since midnight
HLRZ T,2 ;The year
SUBI T,1900.
DPB T,[330700,,A]
AOS 2
DPB 2,[270400,,A] ;The month
HLRZ T,3 ;The day
AOS T
DPB T,[220500,,A]
] ;END IFN TNX
IFN ITS,[
HLRZ B,A
ANDI B,177777
CAIN B,-1
MOVEI A,0 ;Unknown => start of century
]
PUSH P,A
LDB A,[270400,,0 (P)] ;MONTH 3.9-3.6
CAIG A,12.
CAIG A,0
MOVEI A,1 ;Lisp machine barfs if month is bogus
IDIVI A,10.
MOVEI BYTE,"0(A)
PUSHJ P,(D)
MOVEI BYTE,"0(B)
PUSHJ P,(D)
MOVEI BYTE,"/
PUSHJ P,(D)
LDB A,[220500,,0 (P)] ;DAY 3.5-3.1
CAIG A,31.
CAIG A,0
MOVEI A,1 ;Lisp machine barfs at bogus days now, too
IDIVI A,10.
MOVEI BYTE,"0(A)
PUSHJ P,(D)
MOVEI BYTE,"0(B)
PUSHJ P,(D)
MOVEI BYTE,"/
PUSHJ P,(D)
LDB A,[330700,,0 (P)] ;YEAR 4.7-4.1
IDIVI A,100.
MOVE A,B ;Ignore overflow if 3-digit year (garbage)
IDIVI A,10.
MOVEI BYTE,"0(A)
PUSHJ P,(D)
MOVEI BYTE,"0(B)
PUSHJ P,(D)
MOVEI BYTE,40
PUSHJ P,(D)
HRRZ A,(P) ;TIME
LSH A,-1 ;Half-seconds since midnight, HOW RANDOM!
CAIL A,86400.
MOVEI A,0 ;I suppose the Lisp machine probably checks this too
IDIVI A,60. ;Get number of seconds
PUSH P,B ;Save them
IDIVI A,60. ;Get number of minutes
PUSH P,B ;Save them
REPEAT 3,[ ;Output each of the sections with intervening colons
IDIVI A,10.
MOVEI BYTE,"0(A)
PUSHJ P,(D)
MOVEI BYTE,"0(B)
PUSHJ P,(D)
IFN .RPCNT-2,[
MOVEI BYTE,":
PUSHJ P,(D)
POP P,A
] ;End IFN
] ;End REPEAT
POP P,A
POP P,D
POPJ P,
;Setup for returning a control packet
COMCTL: MOVE BP,[441000,,%CPKDT]
ADD BP,PKTLOC
SETZ BC,
PUSH P,A
MOVEI A,TRANID ;Get current transaction ID
PUSHJ P,COMSTO ;This heads all replies
MOVEI BYTE,40
PUSHJ P,COMCHO
TRNN F,F.FHN ;FILE HANDLE?
JRST COMCT0
MOVE A,DATFHN(IDX) ;YES, GET THE FILE HANDLE
MOVEM A,FHNOUT
MOVEI A,FHNOUT ;AND LEAD WITH IT
PUSHJ P,COMSTO
COMCT0: POP P,A
MOVEI BYTE,40
PUSHJ P,COMCHO ;LEADING SPACE
JRST COMSTO ;OUTPUT THE APPROPRIATE COMMAND AND RETURN
;Send or expect synchronous mark. For output files, A is pointer to routine to be run
; when mark arrives. NOTE: this routine will not work recursivly
COMSSY:
IFN ITS,[
.SUSET [.SPICLR,,[0]] ;To prevent timing screws, turn off all interrupts
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF ;Disable interrupts temporarily to prevent timing lossage
DIR
] ;END IFN TNX
MOVE T,DATSTA(IDX)
TLO T,ST.SYN ;Send synchronous mark
JRST @SSYDSP(T) ;Dispatch on current state
SSYDSP: SSYCLO ;Closed
SSYOPN ;Open
SSYASY ;Async marked
SSYSYN ;Sync marked
SSYEOF ;EOF state
;Sync marked state means that the mark has arrived already. Run the routine here and now.
; A gets replaced with the channel status
SSYSYN: EXCH T,A ;Meanings are reversed
TLZ A,ST.SYN ;No longer marked
IFN ITS,[
.SUSET [.SDF2,,[-1]] ;Defer all channel interrupts
.SUSET [.SPICLR,,[-1]] ;Reenable things like IOC et al
] ;END IFN ITS
PUSHJ P,(T) ;Call routine
MOVEM A,DATSTA(IDX) ;May have changed channel state
IFN TNX,[
;; Since on Tops-20 there is no way to defer only a certain set of interrupts, they
;; will all be left defered. This is a total loss.
MOVEI 1,.FHSLF ;Turn interrupt back on
EIR
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
AIC ;Reenable interrupts on this channel
; MOVEI 1,.FHSLF
; MOVE 2,CHABIT(IDX)
IIC ;Force interrupt on channel to start ball rolling
] ;END IFN TNX
IFN ITS,[
.SUSET [.SDF2,,SSYDF2] ;Restore old DF2 value
MOVE T,CHABIT(IDX)
TRNN IDX,1 ;This an output idx?
JRST SSYSY0 ;Nope, need to cause interrupt to get ball rolling
ANDCAM T,SSYDF2 ;This interrupt is no longer deffered
.SUSET [.SDF2,,SSYDF2]
;;; NOTE: Due to the fact that some packets may be sitting in the buffers but not
;;; interrupting (if we dismissed the interrupt with packets lying around), we
;;; better cause an interrupt to let them get processed
SSYSY0: .SUSET [.SIIFPIR,,T]
] ;END IFN ITS
POPJ P,
;Closed or in EOF state
SSYCLO:
SSYEOF: TRNN IDX,1 ;An input channel?
JRST SSYAS0 ;Yes, cause an interrupt to get the ball rolling
JRST SSYOPN
;Async marked means that interrupts (for output channels) have been deffered.
SSYASY:
IFN ITS,[
TRNN IDX,1 ;This an output channel?
JRST SSYAS0 ;Nope, so no need to undefer
MOVE TT,CHABIT(IDX) ;Get mask bit
ANDCAM TT,SSYDF2 ;Undefer
.SUSET [.SDF2,,SSYDF2]
SSYAS0: MOVE TT,CHABIT(IDX)
.SUSET [.SIIFPIR,,TT] ;Cause interrupt to happen right now
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
AIC ;Reenable interrupts on this channel
SSYAS0: MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
IIC ;Force interrupt on channel to start ball rolling
] ;END IFN TNX
; JRST SSYOPN ;Fall into SSYOPN
;Open just needs to set bit
SSYOPN: MOVEM T,DATSTA(IDX)
MOVEM A,DATSYA(IDX) ;A is pointer to action to be taken upon receipt/transmission
IFN ITS,[
.SUSET [.SPICLR,,[-1]] ;Reenable the world
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
EIR ;Turn the interrupt system back on
] ;END IFN TNX
POPJ P,
;;; Send the control packet that has been built in CTLPKO
COMSND: MOVEI T,CO%TXT
COMSN1: DPB T,[$CPKOP+CTLPKO]
DPB BC,[$CPKNB+CTLPKO]
IFN ITS,[
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIMM,,CTRLO
%CLIMM+%CLEND,,CTLPKO]
.LOSE %LSSYS
POPJ P,
] ;END IFN ITS
IFN TNX,[
MOVE 1,CTLJFN
MOVEI 2,.MOPKS
MOVEI 3,CTLPKO
MTOPR
ERCAL CTLERR
IFN $$LOG,[
SKIPN 1,TRIJFN
POPJ P,
SETO 2,
SETZ 3,
ODTIM
HRROI 2,[ASCIZ " ==>
"] ? SETZ 3,
SOUT
LDB A,[$CPKNB CTLPKO]
MOVE B,[441000,,CTLPKO+%CPKDT]
PUSHJ P,PKTPRT
];$$LOG
POPJ P,
] ;END IFN TNX
IFN ITS,[
;File name reader. Returns in DAT???(IDX)
COMPFN: MOVSI TT,'DSK ;Default device is DSK
MOVEM TT,DATDEV(IDX)
SETZM DATSNM(IDX) ;Default directory is last-used
SETZM DATFN1(IDX) ;No default FN1
MOVSI TT,(SIXBIT />/)
SKIPE STARF2
MOVSI TT,(SIXBIT /*/)
MOVEM TT,DATFN2(IDX)
TRZ F,F.FN1+F.FN2+F.DEV+F.DIR
COMPF0: PUSHJ P,COMSYL ;Read next sixbit frob, BYTE has terminator
JUMPE A,COMPF1
CAIN BYTE,":
JRST [ MOVEM A,DATDEV(IDX) ? TRO F,F.DEV ? JRST COMPF0 ]
CAIN BYTE,";
JRST [ MOVEM A,DATSNM(IDX) ? TRO F,F.DIR ? JRST COMPF0 ]
SKIPN DATFN1(IDX)
JRST [ MOVEM A,DATFN1(IDX) ? TRO F,F.FN1 ? JRST COMPF1 ]
MOVEM A,DATFN2(IDX)
TRO F,F.FN2
COMPF1: CAIN BYTE,215 ;Terminate on newline
JRST COMEUN
JRST COMPF0
] ;END IFN ITS
IFN TNX,[
;;Look for a full file specification
COMGJF: MOVE 2,BP ;Source of filename
PUSHJ P,COMEUS ;Find end of filename
JRST [TRZN F,F.NWL ;Must be terminated with a newline
JRST COMBAD
JRST .+2]
JRST .-2 ;Terminated by space, so keep searching
SETZ 1,
DPB 1,BP ;Insure terminating NULL
COMGJG: PUSH P,2 ;Save BP in case we need to re-try something.
MOVE 1,[GJ%SHT+.GJDEF] ;Setup flags to GTJFN
TLNE D,ST.OUT
SKIPGE NOTNEW
TLOA 1,(GJ%OLD) ;Input or know-to-be-existing file...
JRST [ TLO 1,(GJ%NEW)
SKIPG NOTNEW
TLO 1,(GJ%FOU)
JRST .+1 ]
TLNE D,ST.DIR
JRST [ TLO 1,(GJ%IFG)
JRST COMGJ1] ;Allow wild cards for directory
TLNE D,ST.TEM ;Temporary file?
TLO 1,(GJ%TMP)
COMGJ1: TLNE D,ST.DEL ;Permit deleted file?
TLO 1,(GJ%DEL)
TLNE D,ST.PON
JRST [ TLO 1,(GJ%OFG)
TLZ 1,(GJ%OLD)
JRST .+1] ;Parse only if so desired
COMGJ2: GTJFN
SKIPA ;JSYS error, return it to user
AOS -1(P)
POP P,2 ;Leave AC2 pointing to the filename...
POPJ P,
COMGDJ: MOVE 2,BP ;Source of filename
PUSH P,2
PUSHJ P,COMEUS ;Find end of filename
JRST [TRZN F,F.NWL ;Must be terminated with a newline
JRST COMBAD
JRST .+2]
JRST .-2 ;Terminated by space, so keep searching
SETZ 1,
DPB 1,BP ;Insure terminating NULL
MOVSI 1,(GJ%OLD\GJ%IFG)
TLNE D,ST.DEL ;Permit deleted file?
TLO 1,(GJ%DEL)
TLNE D,ST.PON ;Parse-only?
TLC 1,(GJ%OFG\GJ%OLD\GJ%IFG)
HLLM 1,JFNBLK
MOVEI 1,JFNBLK
JRST COMGJ2
] ;END IFN TNX
;Read a syllable
COMSYL: SETZ A,
MOVE TT,[440600,,A]
COMSY3: SOJL BC,COMBAD ;If no more bytes then done
ILDB BYTE,BP
CAIE BYTE,^Q ;Allow ^V to quote too, for the sake of
CAIN BYTE,^V ;20's on which ^Q is an interrupt character.
SKIPA
JRST COMSY1 ;Not quoted char
SOJL BC,COMBAD
ILDB BYTE,BP
JRST COMSY2
COMSY1: CAIE BYTE,": ;Colon, semicolon and space and control chars end syllable
CAIN BYTE,";
JRST CPOPJ
CAIN BYTE,215
JRST COMEUN
CAIN BYTE,40 ;Space ends syllable if not quoted
JRST CPOPJ
COMSY2: CAIGE BYTE,40 ;Control chars end syllable even if ^Q'd.
POPJ P,
CAIGE BYTE,140 ;Skip if "lower case"
SUBI BYTE,40
TLNE TT,770000
IDPB BYTE,TT
JRST COMSY3
COMOCI: SKIPA T,[8]
;;; Decimal number reader
COMDCI: MOVEI T,10. ;Read in BASE 10
COMNUI: SETZ A,
COMNU0: SOJL BC,CPOPJ
ILDB BYTE,BP
CAIL BYTE,"0
CAIL BYTE,"0(T)
JRST COMEUA
IMULI A,(T)
ADDI A,-"0(BYTE)
JRST COMNU0
;;; Sixbit input. Raise case of letters. Terminate on space or non-sixbit.
COMSXI: MOVEI T,6. ;Maximum of 6 chars
MOVE TT,[440600,,A] ;Collect in A
SETZ A,
COMSI0: SOJL BC,CPOPJ ;Return if nothing more to read
ILDB BYTE,BP
CAIL BYTE,"a
CAILE BYTE,"z
SKIPA
SUBI BYTE,"a-"A
SUBI BYTE,40 ;Convert to sixbit
JUMPLE BYTE,CPOPJ ;Return if it's a non-sixbit character or space
CAILE BYTE,77
POPJ P,
SOJL T,COMSI0 ;Don't stick in if no more room
IDPB BYTE,TT
JRST COMSI0
;;; Date input
IFN ITS,[ ;This only allows MM/DD/YY HH:MM:SS
COMDTI: SETZ A,
PUSHJ P,COMDT1
DPB T,[270400,,A] ;Month 3.9-3.6
PUSHJ P,COMDT1
DPB T,[220500,,A] ;Day 3.5-3.1
PUSHJ P,COMDT1
DPB T,[330700,,A] ;Year 4.7-4.1
CAIN BYTE,215 ;If no newline, then no time
JRST COMEUN
PUSHJ P,COMDT1 ;Hours
MOVE B,T
PUSHJ P,COMDT1 ;Minutes
IMULI B,60.
ADD B,T
PUSHJ P,COMDT1 ;Seconds
IMULI B,60.
ADD B,T
LSH B,1 ;Half seconds
HRR A,B
POPJ P,
COMDT1: SETZ T,
COMDT2: SOJL BC,CPOPJ
ILDB BYTE,BP
CAIL BYTE,"0
CAILE BYTE,"9
POPJ P,
IMULI T,10.
ADDI T,-"0(BYTE)
JRST COMDT2
] ;END IFN ITS
IFN TNX,[
COMDTI: MOVE 1,BP ;Source of date
PUSHJ P,COMEUS ;Find end
JRST [TRZN F,F.NWL ;Must be terminated with a newline
JRST COMBAD
JRST .+2]
JRST .-2 ;Terminated by space, so keep searching
SETZ 2,
DPB 2,BP ;Insure terminating NULL
IDTIM
ERCAL JSYSER
MOVE A,2
POPJ P,
] ;END IFN TNX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; For a JSYS that might get an access violation, try it, and if it
;;; fails, see if you can CONNECT no password, and if so, try the
;;; JSYS again.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFN 20X,[
TRYCON: PUSH P,1 ;Save arg in AC1 which might be clobbered by error.
PUSH P,A ;Save temp
HRRZ A,-2(P) ;Get return addr, which should be addr of JSYS
XCT (A)
ERJMP [CAIN 1,DELFX1 ;DELF errors (delete access required)
JRST CONECT
CAIN 1,RNAMX8 ;RNAMF errors (write or owner on source)
JRST CONECT
CAIE 1,OPNX3 ;OPENF errors (read, write, execute,
CAIN 1,OPNX4 ;or append access required).
JRST CONECT
CAIE 1,OPNX5
CAIN 1,OPNX6
JRST CONECT
CAIN 1,CFDBX3 ;CHFDB error (write or owner access)
JRST CONECT
JRST CONLUZ ] ;Not an error we know.
POP P,A ;We win. Clean the stack,
POP P,1
AOS (P) ;and skip-return past the JSYS (and its
JRST POPJ1 ;trailing error jump)
CONECT: PUSH P,2
HRROI 1,CONFNM
MOVEM 1,RESBLK+.ACDIR
HRRZ 2,DATJFN(IDX) ;JFN
MOVE 3,[.JSAOF_33.+.JSAOF_30.+JS%PAF]
JFNS ;Get DEV:<DIRECTORY> into CONFNM
ERJMP CONLZ1
SETZM RESBLK+.ACPSW ;No password ...
SETOM RESBLK+.ACJOB ;This job.
MOVE 1,[AC%CON+3] ;AC%CONnext to dir, 3 word arg block.
MOVEI 2,RESBLK ;Address of block.
ACCES
ERJMP CONLZ1
SETOM CNCTED
POP P,2 ;Clean the stack...
POP P,A ;and return to the JSYS
POP P,1
POPJ P,
CONLZ1: POP P,2 ;CONECT failed
CONLUZ: AOS -2(P) ;Address of instruction after JSYS
HLRZ A,@-2(P)
CAIN A,(ERCAL) ;Simulate ERCAL
JRST [ HRRZ A,@-2(P)
AOS -2(P) ;Return address for ERCAL
MOVEM A,-1(P)
POP P,A
POPJ P, ]
CAIN A,(ERJMP) ;Simulate ERJMP
JRST [ HRRZ A,@-2(P)
MOVEM A,-2(P)
JRST .+1 ]
POP P,A
SUB P,[1,,1] ;Return error code, not saved 1
POPJ P,
DISCON: SKIPN CNCTED
POPJ P,
SKIPN 1,CWDNUM ;If you are in an explicit CONNECT
MOVE 1,UDRNUM ;state, then return there, else it
MOVEM 1,RESBLK+.ACDIR ;an implicit one, so return to home
SETZM RESBLK+.ACPSW ;dir.
SETOM RESBLK+.ACJOB
MOVE 1,[AC%CON+3]
MOVEI 2,RESBLK
ACCES
ERJMP CPOPJ
SETZM CNCTED
POPJ P,
];20X
;;; Create a new data connection
COMDCN: TRZN F,F.FHN ;MUST NOT HAVE A FILE HANDLE
TRZE F,F.NWL ;NEWLINE TERMINATES COMMAND?
JRST COMBAD ;ILLEGAL REQUEST FORMAT
PUSHJ P,COMRD5 ;READ THE NEXT TOKEN, WHICH SHOULD BE THE INPUT FILE HANDLE
JRST COMBAD
PUSH P,A ;SAVE ON STACK
PUSHJ P,COMRD5 ;NEXT TOKEN AS WELL
TRZE F,F.NWL ;BETTER HAVE GOTTEN TO END OF PACKET
JRST COMBAD ;NOT END OF PACKET, BUT DIDN'T WANT ANY MORE CRUFT
MOVEI IDX,MAXIDX-2 ;CHECK FOR A FREE DATA CONNECTION
COMDC2: SKIPN DATFHN(IDX) ;BOTH FILE HANDLE'S NULL MEANS A FREE ONE
SKIPE DATFHN+1(IDX)
JRST COMDC1 ;NOT FREE, CONTINUE SEARCHING
MOVEM A,DATFHN+1(IDX) ;OUTPUT FILE HANDLE
POP P,DATFHN(IDX) ;AND INPUT FILE HANDLE
MOVEM A,FHNOUT ;FILE HANDLE TO RFC TO: USE THE OUTPUT SIDE
IFN ITS,[
.CALL [ SETZ
SIXBIT /CHAOSO/
%CLIN,,CHACHN+1(IDX)
%CLIN,,CHACHN(IDX)
%CLIMM+%CLEND,,15.]
JRST [ SETZM DATFHN(IDX) ;IDX's not really in use
SETZM DATFHN+1(IDX)
CERR NER,[Not enough Chaosnet channels]]
MOVEI A,FHNOUT ;POINT TO IT
SETZ BC,
MOVE BP,[441000,,CTLPKO+%CPKDT]
PUSHJ P,COMSTO ;STRING-OUT TO PACKET, POINTER TO STRING IN A
MOVEI T,%CORFC
DPB T,[CTLPKO+$CPKOP] ;RFC
DPB BC,[CTLPKO+$CPKNB] ;NUMBER OF BYTES
LDB T,[CTLPKI+$CPKSA]
DPB T,[CTLPKO+$CPKDA]
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIN,,CHACHN(IDX)
%CLIMM+%CLEND,,CTLPKO]
.LOSE %LSSYS
MOVE T,CHABIT(IDX) ;Get input channel bit
IOR T,CHABIT+1(IDX) ;And output channel bit
.SUSET [.SIMSK2,,T] ;Enable interrupts on these channels
] ;END IFN ITS
IFN TNX,[
HRROI 1,JFNSTR ;Build output string
HRROI 2,[ASCIZ \CHA:\]
SETZB 3,4
SOUT
ERCAL SYSBUG
LDB 2,[CTLPKI+$CPKSA] ;Source address
MOVEI 3,8.
NOUT
ERCAL SYSBUG
MOVEI 2,".
IDPB 2,1
HRROI 2,FHNOUT
SOUT ;Now have: CHA:<host>.<contact name>
ERCAL SYSBUG
HRLZI 1,(GJ%SHT) ;Short GTJFN to get the channel
HRROI 2,JFNSTR
GTJFN
ERCAL SYSBUG
HRRZM 1,CHAJFN(IDX) ;This is this idx's input and output JFN
HRRZM 1,CHAJFN+1(IDX)
MOVE 2,[100000,,OF%RD\OF%WR]
OPENF ;Listen for connection
ERCAL SYSBUG
MOVE 1,CHAJFN(IDX) ;Set input window size
MOVEI 2,.MOSWS
MOVEI 3,15
MTOPR
ERCAL SYSBUG
MOVE 1,CHAJFN(IDX) ;Assign interrupt channel
MOVEI 2,.MOACN
MOVE 3,IDX
LSH 3,-1
MOVE 3,CHAICN(3) ;Output,,Input channels
MTOPR
ERCAL SYSBUG
MOVEI 1,.FHSLF ;Activate the interrupt channel
MOVE 2,CHABIT(IDX)
AIC
SETZM DATJFN(IDX)
SETZM DATDSP(IDX)
] ;END IFN TNX
MOVEI A,[ASCIZ \DATA-CONNECTION\]
PUSHJ P,COMCTL ;SEND RESPONSE
PUSHJ P,COMSND ;SEND THE CONTROL PACKET
JRST CTLLOP ;RETURN TO MAIN CONTROL CONNECTION WAIT
COMDC1: SUBI IDX,2
JUMPGE IDX,COMDC2 ;LOOP IF MORE CHANNELS TO CHECK
CERR NER,[Not enough I/O channels]
;;; Destroys a data connection
COMUDC: TRNE F,F.FHN ;Must have a file handle
TRZE F,F.NWL ;Not terminated by newline
JRST COMBAD
JUMPGE BC,COMBAD ;But that's all there is
TRO IDX,1 ;Point to top of two channel pair
SKIPGE DATSTA(IDX) ;Channel active?
PUSHJ P,CLOSIT ;Yes, close it
SETZM DATSTA(IDX) ;Make sure channel is deactivated
TRZ IDX,1 ;Now point to bottom of pair
SKIPGE DATSTA(IDX) ;What about this on. Is it active?
PUSHJ P,CLOSIT ;Yes, close it
SETZM DATSTA(IDX) ;Make sure channel is deactivated
MOVEI A,[ASCIZ \UNDATA-CONNECTION\]
PUSHJ P,COMCTL ;Setup control packet
PUSHJ P,CHNFLS ;Flush the chaos channels
PUSHJ P,COMSND ;Send it
JRST CTLLOP ;Return to main loop
;;; Flush chaos net channels pointed to by IDX. IDX assumed to point
;;; to the input (even) side.
CHNFLS:
IFN ITS,[
MOVE T,CHABIT(IDX)
IOR T,CHABIT+1(IDX)
.SUSET [.SAMSK2,,T] ;Turn off interrupts for the two chaos channels of interest
.CALL [ SETZ
SIXBIT /CLOSE/ ;Close the chaos channels
%CLIN+%CLEND,,CHACHN(IDX)]
.LOSE %LSSYS
.CALL [ SETZ
SIXBIT /CLOSE/
%CLIN+%CLEND,,CHACHN+1(IDX)]
.LOSE %LSSYS
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
DIC ;Disable the interrupt channel
HRRZ 1,CHAJFN(IDX) ;Close and release JFN
CLOSF
JFCL
] ;END IFN TNX
SETZM DATFHN(IDX) ;Make this pair available for a new data connection
SETZM DATFHN+1(IDX)
POPJ P,
;;; LOGIN command
COMLOG: TRZN F,F.FHN ;No file handle
TRZE F,F.NWL ;No newline
JRST COMBAD
IFN ITS,[
PUSHJ P,COMSXI ;Read user id in sixbit
MOVEM A,USERID ;Remember for later
MOVEI A,[ASCIZ \LOGIN \]
PUSHJ P,COMCTL
SKIPE A,USERID
PUSHJ P,GETNAM ;Output uname, hsname and personal name
.SUSET [.SSNAME,,HSNAME] ;Initialize default directory
.SUSET [.SHSNAM,,HSNAME] ; and home directory
.SUSET [.SXUNAM,,USERID] ; and user name
] ;END IFN ITS
IFN TNX,[
SKIPN ANONUM
JRST [MOVSI 1,(RC%EMO)
HRROI 2,[ASCIZ "ANONYMOUS"]
RCUSR
TLNE 1,(RC%NOM)
SETO 3,
MOVEM 3,ANONUM ;Anonymous's user#
JRST .+1]
JUMPLE BC,CTLDN0 ;Really logout if no arguments
MOVE 2,BP ;Save copy of byte pointer
PUSHJ P,COMEUS ;Eat until space, newline, or end
JUMPL BC,COMBAD ;End of packet is no good
SETZ T, ;Deposit null to terminate string
DPB T,BP
IFN OZ,[
Push P,2
Skipn GOTINQ ;Inquire database here?
Jrst [Movei A,IPAGE ;No, so map it in now.
Pushj P,HAKINQ"MAPIN
Jrst BADINQ
Setom GOTINQ
Move A,(P)
Jrst .+2]
Move A,2
Pushj P,HAKINQ"XLATE ;Lookup and turn into user#
Jrst BADINQ
Movem A,INQADR ;Save address of inquire entry
Movem B,USRNUM ;and user#
Pop P,2
Jrst COMLCC
BADINQ: Setzm INQADR ;0 means we have no Inquire information.
Pop P,2
];OZ Inquire login
MOVSI 1,(RC%EMO) ;Exact match
RCUSR
ERJMP .+2
TLNE 1,(RC%NOM) ;Matched?
CERR UNK,[User not known]
MOVEM 3,USRNUM ;Save user number
COMLCC:
IFN 20X,[
IFN $$CCUC,[ ;and then only if turned on at assembly time
MOVEI 1,.FHSLF ;Must enable for GTDIR
RPCAP
MOVE 3,2
EPCAP
MOVEI 1,0
MOVE 2,USRNUM
RCDIR ;Get dir number
MOVE 1,3
MOVEI 2,DIRINF ;Discover user's capabilities
MOVEI 3,0
SETZM DIRINF
GTDIR
ERCAL SYSBUG
MOVEI 1,.SFCHA ;See if Chaosnet checking is on
TMON
ERJMP COMLG1 ;Not even implemented - skip check
JUMPE 2,COMLG1 ;It's off - skip the check
MOVE 1,DIRINF+.CDPRV ;Check for Chaos net privilege
TRNN 1,SC%CHA
CERR LIP,[No Chaosnet privileges]
COMLG1:
] ;END IFN $$CCUC
] ;END IFN 20X
PUSHJ P,ANONPW
JRST COMLGP ;Need a password, rats.
HRROI 2,JFNSTR
SETZB 3,T ;No account given
JRST COMLG4
COMLGP: MOVE 1,USRNUM ;Recover your old usernumber.
MOVE 2,BP ;Beginning of password string
ILDB 3,2 ;Get and save first char
TRZ F,F.ENA
CAIN 3,"* ;Is first letter * ?
TROA F,F.ENA ;Enable
SKIPA 2,BP ;Remember unbumped version
MOVE BP,2 ;Update BP to skip *
IFN 10X, MOVE 3,BP ;Keep a copy to do uppercasing
PUSHJ P,COMEUS ;Find next terminating character
JFCL
IFN 10X,[ ;Tenex LOGIN expects uppercase?
COMLGU: CAMN 3,BP ;Until end of this string
JRST COMLG0
ILDB T,3 ;Get a character of the password
CAIL T,"a ;and force it to be uppercase
CAILE T,"z
CAIA
SUBI T,40
DPB T,3 ;Store back the uppercased char
JRST COMLGU
COMLG0:
];END IFN 10X
SETZ T,
DPB T,BP ;Terminate password with null byte
MOVE 3,BP ;This is account string
PUSHJ P,COMEUS ;Then find end of string
JUMPGE BC,COMBAD
SETZ T,
DPB T,BP ;Terminate with null byte
IDPB T,BP ;In case no acct string given
MOVE T,3
ILDB T,T
IFN 20X,[
SKIPN T
SETZ 3, ;Use default if empty string
];20X
COMLG4:
IFN 10X,[
JUMPN T,COMLG3
PUSH P,2 ;Save password string
MOVEI 1,DIRINF ;Where to put account designator if string
MOVE 2,USRNUM
GDACC
SETZ 1, ;Doesn't seem to have a default, will get error
MOVE 3,1 ;Number or byte pointer
POP P,2 ;Get back password
COMLG3: MOVE 1,USRNUM
];10X
SKIPGE DEBUG
JRST [ PUSHJ P,$HELLO ;If debugging, don't do real login, or enable
JRST COMLG2]
PUSHJ P,$LOGIN
PUSHJ P,JSYSER
IFN OZ,[ ;This doesn't do what we want, alas.
IFN 0,[
TRNE F,F.LSP
JRST [MOVEI 1,.FHSLF ;((IFF LISPMACHINE)) --
RPCAP ;Now that you're logged in, read your
MOVE 3,2 ;capabilities, and limit yourself to
EPCAP ;them.
JRST .+1]
];IFN 0
];OZ
COMLG2: MOVEI A,[ASCIZ \LOGIN \] ;Success reply
PUSHJ P,COMCTL
PUSHJ P,GETNAM
] ;END IFN TNX
PUSHJ P,COMSND ;Completion reply
JRST CTLLOP ;Then we are done
;;; Auto-login (as Q.SITE or failing that, ANONYMOUS)
;;; This was not thought out. It needs to be redone.
IFN OZ,[
AUTLOG: CERR NLI,[Not logged in]
IFN 0,[
AUTLOG: PUSHJ P,SITEPW ;try to login as <Q.hostname>
JRST ANNLOG ;Urg, no password file.
HRROI 2,JFNSTR
PUSHJ P,$LOGIN
SKIPA ;double urg, it's WRONG!!
POPJ P, ;ahhh...
ANNLOG: SETZM USRNUM
PUSHJ P,ANONPW ;Can we can login as Anonymous w/o Password?
CERR NLI,[Can't defaultly log you in - no password file]
HRROI 2,JFNSTR
PUSHJ P,$LOGIN ;Login then,
CERR NLI,[Can't defaultly log you in - incorrect password file]
];IFN 0
POPJ P,
];OZ
IFN TNX,[
;;; Log you in as user#(USERNUM), and turn on what privs you have (or else
;;; leave them all on - See the F.ENA flag in F) - Also, set USERID to
;;; reflect loggedinness. Set subsystem name to "FILE".
$LOGIN: LOGIN ;Login with specified parameters
POPJ P, ; LOSSAGE
AOS (P) ;Will take success return
GJINF ;Directory# in AC2
MOVEM 1,USRNUM
MOVEM 2,UDRNUM
TRZN F,F.ENA ;If you want to be priv, don't limit
JRST $HELLO ; yourself, but keep full privs.
MOVEI 1,.FHSLF
RPCAP
MOVE 3,2
EPCAP ;Enable what capabilities you have.
$HELLO: SETOM USERID ;Means we are logged in
;Now attempt to access all structures
IFN 20X,[
PUSH P,C
PUSH P,D
MOVE 1,[SIXBIT /DEVNAM/]
SYSGT
HRRZ D,2 ;Table#
MOVEI C,1 ;Should be 1st device name.
ACCST1: HRLZ 1,C
HRR 1,D ;Offset,,table#
GETAB
JFCL
;;[UTexas] The following won't work if # of strs is maximum allowed by monitor
;; HLRZ 2,1 ;If no more devices, it's SIXBIT/STRnnn/
;; CAIN 2,(SIXBIT /STR/)
;; JRST ACCST9
MOVE 3,[440700,,DIRINF]
ACCST2: SETZ 2, ;Turn sixbit structure name into asciz
ROTC 1,6 ;string.
ADDI 2,40
IDPB 2,3
JUMPN 1,ACCST2
MOVEI 1,":
IDPB 1,3
MOVEI 1,"<
IDPB 1,3
MOVE 1,3 ;Set directory name from our user name
MOVE 2,USRNUM
DIRST
ERJMP ACCST9
MOVEI 3,">
IDPB 3,1 ;Terminate user directory
SETZ 3, ;Null to terminate string
IDPB 3,1
;;Start of UTexas change
PUSH P,1 ;Save BP
HRROI 1,DIRINF ;Set up to get device designator
STDEV
ERJMP [POP P,1
JRST ACCST9]
MOVE 1,2 ;Set up device designator
DVCHR ;Check device type
ERJMP [POP P,1
JRST ACCST9]
POP P,1 ;Restore BP
LDB 3,[221100,,2] ;Get DV%TYP
CAIE 3,.DVDSK ;Is it a disk?
JRST ACCST9 ;No, done
;;End of UTexas changes
HRRZ 2,1 ;Get argument block after dir name
ADDI 2,1 ;First unused word after dir that is
MOVE 1,[440700,,DIRINF] ;Directory name string
MOVEM 1,0(2) ;Store as first word of arg block
SETZM 1(2) ;No password supplied
SETOM 2(2) ;And for this job
MOVE 1,[200000,,3] ;Setup for ACCES call
ACCES ;Attempt the Access
ERJMP .+1 ;So what if it fails
ACCST8: AOJA C,ACCST1 ;Step to next structure.
ACCST9: POP P,D
POP P,C
IFN $$LNM,[ ;Maybe Process LOGICALS.CMD
lnm: move 2,USRNUM
hrli 2,540000 ;Make into directory #
hrroi 1,strbuf
DIRST
erjmp lnm11
move 2,[440700,,[asciz/LOGICALS.CMD/]]
ildb 3,2
idpb 3,1
jumpn 3,.-2
hrroi 2,strbuf
movsi 1,(gj%sht\gj%old)
GTJFN
erjmp lnm11
hrlm 1,cmdblk+.CMIOJ
move 2,[.dpb 7,.bp of%bsz,of%rd]
OPENF
erjmp [hlrz 1,cmdblk+.CMIOJ
RLJFN
erjmp lnm11
jrst lnm11]
lnm1: movei 1,strbsz
movem 1,cmdblk+.CMABC
move 1,[440700,,atmbuf]
movem 1,cmdblk+.CMABP
movei 1,cmdblk
movei 2,[.cmini_9,,0 ? 0 ? 0 ? 0 ? 0]
COMND
erjmp lnm10
movei 2,[.cmkey_9,,0 ? [1,,1 ? [asciz/DEFINE/],,0] ? 0 ? 0 ? 0]
COMND
erjmp lnm10
tlne 1,(cm%nop)
jrst lnm1
;Some people like to put in the noise words in the command file
movei 2,[.cmnoi_9,,0 ? 440700,,[asciz/logical name/] ? 0 ? 0 ? 0]
COMND
erjmp lnm10
tlne 1,(cm%nop)
jrst lnm1
movei 2,[<(cm%po)\.cmdev_9>,,[.cmtok_9,,0 ? 440700,,[asciz/*/] ? 0 ? 0 ? 0]
0 ? 0 ? 0 ? 0]
COMND
erjmp lnm10
tlne 1,(cm%nop)
jrst lnm1
hlrz 3,(3)
movei 4,.CLNJA ;"def *" means delete all logical names
cain 3,.cmtok_9
jrst lnm4 ;Yup
move 3,cmdblk+.CMABC ;Else find end of the device name
move 4,cmdblk+.CMABP
ildb 2,4
soj 3,
jumpn 2,.-2
movem 3,cmdblk+.CMABC ;Will put equivalent name after the device
movem 4,cmdblk+.CMABP
movei 2,[.cmnoi_9,,0 ? 440700,,[asciz/as/] ? 0 ? 0 ? 0]
COMND
erjmp lnm10
tlne 1,(cm%nop)
jrst lnm1
movei 2,[.cmcfm_9,,[.cmtxt_9,,0 ? 0 ? 0 ? 0 ? 0] ? 0 ? 0 ? 0 ? 0]
COMND
erjmp lnm10
tlne 1,(cm%nop)
jrst lnm1
hlrz 3,(3)
movei 4,.CLNJ1 ;"def name:<cr>" means just delete the name
cain 3,.cmcfm_9
jrst lnm5 ;Yup
movei 4,.CLNJB ;Else have a name to define
lnm4: movei 2,[.cmcfm_9,,0 ? 0 ? 0 ? 0 ? 0]
COMND
erjmp lnm10
tlne 1,(cm%nop)
jrst lnm1
lnm5: move 1,4
move 2,[440700,,atmbuf]
move 3,cmdblk+.CMABP
CRLNM
erjmp .+1
jrst lnm1
lnm10: hlrz 1,cmdblk+.CMIOJ
CLOSF
erjmp lnm11
lnm11:
];$$LNM
];20X
POPJ P,
];TNX
;;; HOMEDIR command
COMHOM: TRZN F,F.FHN ;No file handle
TRZE F,F.NWL ;No newline
JRST COMBAD
IFN ITS,[
PUSHJ P,COMSXI ;Read user id in sixbit
PUSH P,A ;Save uname
PUSHJ P,GETINQ ;Get inquir entry address in B
SETZ B, ;Not found
POP P,A
SETZ C, ;Now find HSNAME for local host.
MOVEI D,ERRCH
PUSHJ P,LSRTNS"LSRHSN ;D gets the sixbit HSNAME.
JFCL
MOVEI A,[ASCIZ \HOMEDIR \]
PUSHJ P,COMCTL
MOVE A,D ;HSNAMEP
PUSHJ P,COMSXO
MOVEI BYTE,";
PUSHJ P,COMCHO
PUSHJ P,UNGINQ
PUSHJ P,COMSND
JRST CTLLOP
];ITS
IFN TNX,[
MOVE 2,BP ;BP to start of user name
PUSHJ P,COMEUS ;Eat until space, newline, or end
SKIPGE BC
IBP BP ;No delimiter
SETZ T, ;Deposit null to terminate string
DPB T,BP
IFE OZ,[
MOVSI 1,(RC%EMO) ;Exact match
RCUSR
ERCAL SYSBUG ;Monitor internal errors I guess
TLNE 1,(RC%NOM) ;Matched?
CERR UNK,[User not known]
PUSH P,3 ;Save user number
MOVEI A,[ASCIZ \HOMEDIR \] ;Always succeeds if we get here
PUSHJ P,COMCTL
MOVSI 1,(GJ%OLD\GJ%SHT)
IFN 20X,HRROI 2,[ASCIZ /SYS:PEOPLE.DATA/]
IFN 10X,HRROI 2,[ASCIZ /<INQUIR>PEOPLE.DATA/]
PUSH P,[0]
GTJFN
JRST COMHM3
MOVEM 1,(P) ;Save jfn
MOVE 2,[440000,,OF%RD]
OPENF
JRST COMHM3
HRRZ 3,-1(P) ;User number
RIN
JUMPE 2,COMHM3 ;No information on this user
HLRZ 3,2
HRRZS 2
SFPTR
JRST COMHM3
CAILE 3,INQBLL
MOVEI 3,INQBLL
MOVN 3,3
MOVE 2,[444400,,INQBLK]
SIN ;Get all data on the person
MOVE A,[440600,,INQBLK+1] ;Byte counts
MOVE B,[440700,,INQBLK+4] ;String starts
SETZ C, ;Current field.
MOVEI T,$DNAME
PUSHJ P,GETFLD ;Output directory name followed by a CR
COMHM2: SKIPE 1,(P) ;Release inquir file
CLOSF
JFCL
PUSHJ P,COMSND
JRST CTLLOP
COMHM3: HRROI 1,RESBLK ;No inquir entry, default to user's name
MOVE 2,-1(P) ;User number
IFN 20X,TLO 2,40000
DIRST
JFCL
PUSHJ P,COMRES
JRST COMHM2
];Regular TOPS-20
IFN OZ,[
Push P,2 ;Save copy of BP
Skipn GOTINQ ;Inquire database here?
Jrst [Movei A,IPAGE ;No, so map it in now.
Pushj P,HAKINQ"MAPIN
Jrst NoSUsr
Setom GOTINQ
Jrst .+1]
Move A,(P)
Pushj P,HAKINQ"XLATE ;Lookup and turn into user#
Jrst NoSUsr
Move 3,B
Adjsp P,-1
Jrst UserNo
NoSUsr: Movsi 1,(RC%EMO)
Pop P,2
RCUSR
Erjmp .+2
Tlne 1,(RC%NOM)
CERR UNK,[User not known]
UserNo: Hrroi 1,RESBLK
Move 2,3
Hrli 2,540000 ;PS: LH
DIRST
Nop
Movei A,[Asciz "HOMEDIR "]
Pushj P,COMCTL
Pushj P,COMRES
Pushj P,COMSND
Pushj P,CLOINQ
Jrst CTLLOP
];OZ HOMEDIR from new Inquire
];TNX
IFN ITS,[
;;; INQUIR hacking
$$ULNM==0
$$ULNP==0
$$UNAM==0
$$HSNM==1
LSRTNS"E==T
LSRPGS==200 ;Pages for LSRTNS hacking
NLSPGS==20 ;Reserve 20 of them
.INSRT SYSENG;LSRTNS >
;;; Output UNAME<SP>HSNAME<NL>PERNAM<NL>GROUP
GETNAM: PUSH P,B
PUSH P,C
PUSH P,D
PUSH P,A
PUSHJ P,GETINQ
JRST [SETZ B, ;No entry there
MOVE A,(P) ;UNAME
PUSH P,B
PUSHJ P,COMSXO
JRST GETNM1] ;And go compute HSNAME.
MOVE A,(P) ;UNAME in A, core addr still in B.
PUSH P,B ;Save INQUIRE entry address
PUSHJ P,COMSXO ;Output UNAME.
GETNM1: MOVEI BYTE,40
PUSHJ P,COMCHO ;SP.
MOVE A,-1(P) ;Username
MOVE B,(P) ;INQUIR entry
SETZ C, ;Now find HSNAME for local host.
MOVEI D,ERRCH
PUSHJ P,LSRTNS"LSRHSN ;D gets the sixbit HSNAME.
JFCL
MOVE A,D ;Get answer.
MOVEM A,HSNAME
PUSHJ P,COMSXO ;Output HSNAME or nothing.
MOVEI BYTE,215
PUSHJ P,COMCHO ;NL.
MOVEI A,LSRTNS"I$NAME
MOVE B,(P) ;INQUIRE entry
PUSHJ P,LSRTNS"LSRITM ;Get personal name.
JRST [ MOVE A,[440700,,[ASCIZ /???/]]
JRST .+1 ]
PUSHJ P,COMST0 ;Output PERNAM or nothing.
MOVEI BYTE,215
PUSHJ P,COMCHO ;NL
MOVEI A,LSRTNS"I$GRP
POP P,B ;INQUIRE entry
PUSHJ P,LSRTNS"LSRITM ;Get Group affiliation.
JRST [ MOVE A,[440700,,[ASCIZ /-/]]
JRST .+1 ]
PUSHJ P,COMST0 ;Output GROUP.
UNMAPL: PUSHJ P,UNGINQ
POP P,A
POP P,D
POP P,C
POP P,B
POPJ P,
;Get INQUIR entry for uname on the stack, and skip return with inquir entry address in B
GETINQ: MOVEI A,UTILCH ;Channel for LSRTNS
MOVE B,[-NLSPGS,,LSRPGS]
PUSHJ P,LSRTNS"LSRMAP
JRST [CERR NER,[Cannot map INQUIR database]] ;Random error
MOVEI A,UTILCH ;Channels for INQUIR database
MOVE B,-1(P) ;B gets sixbit UNAME.
JRST LSRTNS"LSRUNM ;Map in the LSRTNS entry
;Flush inquir data base
UNGINQ: MOVE B,[-NLSPGS,,LSRPGS]
.CALL [ SETZ ;Done with these
SIXBIT /CORBLK/
%CLIMM,,0
%CLIMM,,%JSELF
SETZ B]
JFCL
.CLOSE UTILCH,
.CLOSE ERRCH,
POPJ P,
] ;END IFN ITS
IFN TNX,[
;;; INQUIR hacking
;;; Output USERNAME<SP>DIRECTORY<NL>PERSONAL NAME<NL>GROUP
IFE OZ,[
$DNAME==0
$HNAME==1
$GROUP==14
GETNAM: HRROI 1,RESBLK
MOVE 2,USRNUM
DIRST
JFCL
MOVEI 2,0
IDPB 2,1
PUSHJ P,COMRES ;Output user name
MOVEI BYTE,40
PUSHJ P,COMCHO
MOVSI 1,(GJ%OLD\GJ%SHT)
IFN 20X,HRROI 2,[ASCIZ /SYS:PEOPLE.DATA/]
IFN 10X,HRROI 2,[ASCIZ /<INQUIR>PEOPLE.DATA/]
PUSH P,[0]
GTJFN
JRST GETNM3
MOVEM 1,(P) ;Save jfn
MOVE 2,[440000,,OF%RD]
OPENF
JRST GETNM3
HRRZ 3,USRNUM
RIN
JUMPE 2,GETNM3 ;No information on this user
HLRZ 3,2
HRRZS 2
SFPTR
JRST GETNM3
CAILE 3,INQBLL
MOVEI 3,INQBLL
MOVN 3,3
MOVE 2,[444400,,INQBLK]
SIN ;Get all data on the person
MOVE A,[440600,,INQBLK+1] ;Byte counts
MOVE B,[440700,,INQBLK+4] ;String starts
SETZ C, ;Current field.
MOVEI T,$DNAME
PUSHJ P,GETFLD
MOVEI T,$HNAME
PUSHJ P,GETFLD
IFN OZ,[ ;Only OZ has groups, but OZ doesn't use this code anymore
MOVEI T,$GROUP
PUSHJ P,GETFLD
];OZ
GETNM2: POP P,1
JUMPE 1,CPOPJ
CLOSF
JFCL
POPJ P,
GETFLD: CAMN C,T
JRST GETFL1
ILDB 1,A
GETFL0: SKIPG 1
AOJA C,GETFLD
ILDB 2,B
SOJA 1,GETFL0
GETFL1: ILDB T,A
GETFL2: SKIPG T
AOJA C,GETFL3
ILDB BYTE,B
PUSHJ P,COMCHO
SOJA T,GETFL2
GETFL3: MOVEI BYTE,215
JRST COMCHO
];Non-OZ TOPS-20 Inquire lookup stuff
IFN OZ,[
GETNAM: Skipn INQADR ;We have Inquire information?
Jrst GETNM3 ; Nope.
IFN 0,[
Move A,INQADR ;Address of start of entry
ADD A,HAKINQ"SRDAT ;point to data portion
repeat hakinq"%uname,[ ;Find uname
ildb 1,A
jumpn 1,.-1
]
Pushj P,COMSTO
]
.ELSE [
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Hrroi 1,RESBLK ;** Flush
Move 2,USRNUM ;** this
DIRST ;** when
Nop ;** LMs
Pushj P,COMRES ;** no
Move A,INQADR ;** longer
Add A,HAKINQ"SRDAT ;** compare
repeat hakinq"%dname,[ ;** usernames
Ildb 1,A ;**
Jumpn 1,.-1 ;**
]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
]
Movei Byte,40
Pushj P,COMCHO
Pushj P,COMST0 ;(cheat, 'cause directory's next)
Movei Byte,215
Pushj P,COMCHO
Move B,A ;Yet MORE cheating, 'cause personal-name
Hrroi A,RESBLK ;comes next
Pushj P,HAKINQ"NPNAME ;(translate into human form)
Jfcl
Pushj P,COMRES ;Output from RESBLK
Movei Byte,215
Pushj P,COMCHO
Movei 2,HAKINQ"%GROUP-HAKINQ"%PNAME ;Number of fields we need to skip
Sojl 2,COMLGG
Ildb 1,B
Jumpn 1,.-1
Jrst .-3
COMLGG: Ildb Byte,B ;First character of group.
Skipe Byte ;No group?
Pushj P,COMCHO ; Yes, so output character.
Movei Byte,215
Pushj P,COMCHO ;then all done.
CLOINQ: Skipn GOTINQ ;If have Inquire database open
Popj P, ; (we don't)
Call HAKINQ"MAPOUT ;then unmap
Skipa ; (failed??)
Setzm GOTINQ ; and mark as disposed of.
Popj P,
];OZ Inquire lookup.
;;; No INQUIR information
GETNM3:
IFN OZ,[ ;OZ forgot to send this already
HRROI 1,RESBLK ;User name
MOVE 2,USRNUM
DIRST
JFCL
PUSHJ P,COMRES
MOVEI BYTE,40
PUSHJ P,COMCHO
];OZ
HRROI 1,RESBLK ;Directory name
MOVE 2,USRNUM
IFN 20X,TLO 2,40000
DIRST
JFCL
PUSHJ P,COMRES
MOVEI BYTE,215
PUSHJ P,COMCHO
MOVEI A,[ASCIZ /???/]
PUSHJ P,COMSTO
MOVEI BYTE,215
PUSHJ P,COMCHO
IFE OZ, JRST GETNM2
IFN OZ, Jrst CLOINQ
;;; Before auto-logging as ANONYMOUS, try to login as Q.yourhostname,
;;; which is easier to track. The password is in <Q>yourhostname.PASSWORD.
IFN OZ,[
IFN 0,[
SITEPW: SKIPE KLOGIN
JRST SITEP2
HRROI 1,KLOGIN
HRROI 2,[ASCIZ /Q./]
SETZ 3,
SOUT
HRROI 2,KSITE
SOUT ;Q.hostname in KSITE
SITEP2: MOVSI 1,(RC%EMO)
HRROI 2,KLOGIN
RCUSR
ERJMP CPOPJ ;make sure it exists.
TLNE 1,(RC%NOM)
POPJ P, ; nope. oh well...
MOVEM 3,USRNUM
SKIPE KPASSF
JRST SITEP3
HRROI 1,KPASSF
HRROI 2,[ASCIZ /PS:<Q>/]
SETZ 3,
SOUT
HRROI 2,KSITE
SOUT
HRROI 2,[ASCIZ /.PASSWORD/]
SOUT
SITEP3: HRROI 2,KPASSF
JRST GETPSW
];IFN 0
];OZ
;;; Check out the possibilities of an Anonymous login. If the file seen
;;; below exists, then it contains the password for the Anon account. We
;;; skip-return with password in JFNSTR if we find it, else non-skip. The
;;; user# is stored in USRNUM.
ANONPW: MOVE 1,ANONUM
CAMN 1,[-1]
POPJ P,
SKIPE USRNUM ;If logging in normally, (we already got the USRNUM
CAMN 1,USRNUM ;just return, unless want to be "Anonymous".
SKIPA
POPJ P,
MOVEM 1,USRNUM
IFN 20X,HRROI 2,[ASCIZ /SYSTEM:ANONYMOUS.USERFILE/]
.ELSE HRROI 2,[ASCIZ /<SYSTEM>ANONYMOUS.USERFILE/]
GETPSW: MOVSI 1,(GJ%OLD\GJ%SHT)
GTJFN
POPJ P, ;File not there - Must specify password.
PUSH P,1 ;Save JFN
MOVE 2,[070000,,OF%RD]
OPENF
JRST [ POP P,1 ;Clean stack,
RLJFN ;release JFN,
JFCL
POPJ P, ] ;and fail-return
MOVE 3,[440700,,JFNSTR]
MOVEI 4,39.
COMLA1: BIN
ERJMP COMLA2
CAIG 2,40
JRST COMLA2
IDPB 2,3
SOJG 4,COMLA1
COMLA2: SETZ 2,
IDPB 2,3 ;Make the password string ASCIZ
POP P,1 ;Get back JFN,
CLOSF ;and close the Anonymous userfile.
JFCL
MOVE 1,USRNUM
JRST POPJ1 ;Skip-return -> We win, have Anonymous's password.
];IFN TNX
;;; Open a file
COMOPN: SKIPN USERID ;Has the user logged in?
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
TRZ F,F.PRB\F.DEF\F.PDR
TLZ F,(F.CRE\F.SUP\F.APP\F.OVW\F.NEW\F.REN\F.RND\F.TRU)
TRNN F,F.FHN ;MUST HAVE A FILE HANDLE FOR NORMAL OPEN
JRST OPNPRB ;ELSE MUST BE A PROBE
SKIPGE DATSTA(IDX) ;THIS CHANNEL CURRENTLY ACTIVE?
PUSHJ P,CLOSIT ;YES, CLOSE IT
IFN TNX,[
PUSHJ P,RELDJF ;Dispose of any left-over JFNs this channel is holding
PUSHJ P,RELRJF ;if it err'ed out of a previous open
];TNX
OPNPR0: SETZB D,DATSTA(IDX) ;START OUT FRESH, D WILL CONTAIN NEW LH OF DATSTA
MOVEI T,16. ;DEFAULT DATBYT
MOVEM T,DATBYT(IDX)
MOVEI T,2. ;NUMBER OF BYTES PER WORD
MOVEM T,DATBPW(IDX)
IFN TNX,[
MOVEI T,36. ;Default file byte size
MOVEM T,DATFBS(IDX)
];TNX
SETZM DATRCV(IDX) ;Start at zero bytes received.
OPNOPT: TRNE F,F.NWL ;NEW LINE TERMINATED OPEN COMMAND?
JRST OPNFNM ;YES, DEFAULT OPTIONS, PARSE FILENAME
PUSHJ P,COMR10 ;GET NEXT TOKEN INTO A,B
JUMPL BC,COMBAD
OPNOLP: MOVSI T,-OPNLEN ;LENGTH OF OPEN OPTION TABLE
OPNOL1: CAMN A,OPNTAB(T) ;MATCH?
CAME B,OPNTAB+1(T)
AOBJN T,[AOJA T,OPNOL1]
JUMPGE T,[CERR UUO,[Unknown OPEN option]]
HRRZS T
LSH T,-1
XCT OPNACT(T) ;PERFORM APPROPRIATE ACTION
JRST COMBAD ;ERROR
JRST OPNOPT
OPNTAB: ASCII \READ\ ? 0 ;Read
ASCII \WRITE\ ? 0 ;Write
ASCII \PROBE\ ? 0 ;Probe
ASCII \CHARACTER\ ;Character mode
ASCII \BINARY\ ;Binary mode
ASCII \DEFAULT\ ;Default mode
ASCII \BYTE-SIZE\ ;Byte size specification
ASCII \RAW\ ? 0 ;Raw mode (the bytes as they come)
ASCII \SUPER-IMAG\ ;Super-image -- don't treat rubouts specially
ASCII \SUPER\ ? 0 ;Documented as SUPER-IMAGE but some people send SUPER
ASCII \PRESERVE-D\ ;Preserve-dates
ASCII \INHIBIT-LI\ ;Inhibit-links (ignored except on ITS)
ASCII \DELETED\ ;Deleted files are ok (ignored on ITS)
IFN TNX,[
ASCII \TEMPORARY\ ;Temporary file
ASCII \FILE-BYTE-\ ;file-byte-size
IFN $$SUBM,[
ASCII \SUBMIT\
];$$SUBM
] ;END IFN TNX
ASCII \ESTIMATED-\ ;estimated-length
ASCII \PROBE-DIRE\ ;probe-directory
ASCII \IF-EXISTS\
ASCII \IF-DOES-NO\ ;if-does-not-exist
OPNLEN==<.-OPNTAB>/2
OPNACT: TRNE IDX,1
TRNN IDX,1
TROA F,F.PRB
TLZA D,ST.BIN
TLOA D,ST.BIN
JRST [ TRO F,F.DEF
TLO D,ST.BIN
JRST OPNOPT]
JRST OPNBYS
TLOA D,ST.RAW
TLOA D,ST.SUI
TLOA D,ST.SUI
TLOA D,ST.PDT
TLOA D,ST.INL
TLOA D,ST.DEL
IFN TNX,[
TLOA D,ST.TEM
JRST OPNFBS
IFN $$SUBM,[
JRST OPNSUB
];$$SUBM
] ;END IFN TNX
JRST OPNELN
TROA F,F.PDR
JRST OPNIFE
JRST OPNIDN
IFN <.-OPNACT>-OPNLEN, .ERR OPNTAB and OPNACT not same length
OPNBYS: TRNE F,F.NWL ;BETTER NOT HAVE A NEWLINE
JRST COMBAD
PUSHJ P,COMDCI ;READ A NUMBER FROM THE STREAM
JUMPL BC,COMBAD ;MUST HAVE STUFF LEFT
SKIPLE A ;BYTE-SIZE MUST BE BETWEEN 0 AND 16.
CAILE A,16.
CERR IBS,[Illegal byte size]
MOVEM A,DATBYT(IDX) ;SAVE THE BYTE SIZE
ifn tnx,[
MOVEM A,DATFBS(IDX) ;Save here too
]
MOVE B,A
MOVEI A,36.
IDIV A,B
MOVEM A,DATBPW(IDX) ;REMEMBER BYTES PER WORD
JRST OPNOPT ;AND CONTINUE
IFN TNX,[
OPNFBS: TRNN IDX,1
JRST COMBAD
TRNE F,F.NWL
JRST COMBAD
PUSHJ P,COMDCI
JUMPL BC,COMBAD
SKIPLE A ;File byte size must be between 1 and 36.
CAILE A,36.
CERR IBS,[Illegal file byte size]
MOVEM A,DATFBS(IDX) ;Save it
JRST OPNOPT ;and continue
];TNX
OPNELN: TRNE F,F.NWL ;BETTER NOT HAVE A NEWLINE
JRST COMBAD
PUSHJ P,COMDCI ;READ A NUMBER FROM THE STREAM
JUMPL BC,COMBAD ;MUST HAVE STUFF LEFT
JRST OPNOPT ;Ignore the estimated length and continue
OPNIFE: TRNE F,F.NWL ;Better not have a newline
JRST COMBAD
PUSHJ P,COMR10 ;Get IF-EXISTS mode into A and B
JUMPL BC,COMBAD
MOVSI T,-IFETBL
OPNIF1: CAMN A,IFETAB(T)
CAME B,IFETAB+1(T)
JRST [ ADDI T,2
AOBJN T,OPNIF1
CERR UUO,[Unknown IF-EXISTS option] ]
IOR F,IFETAB+2(T)
JRST OPNOPT
IFN TNX,[
IFN $$SUBMIT,[
OPNSUB: MOVE A,USRNUM
CAMN A,ANONUM
CERR UUO,[Can't SUBMIT when logged in as Anonymous]
TLO D,ST.SUB
JRST OPNOPT
];$$SUBMIT
];IFN TNX
IFETAB: ASCII /SUPERSEDE/ ? F.SUP
IFN TNX,[ ;not implemented for ITS yet
ASCII /APPEND/ ? F.APP
ASCII /OVERWRITE/ ? F.OVW
ASCII /TRUNCATE/ ? F.TRU
ASCII /RENAME/ ? F.REN
ASCII /RENAME-AND/ ? F.RND ;RENAME-AND-DELETE
ASCII /ERROR/ ? 0 ? F.NEW
];TNX
IFETBL==<.-IFETAB>/3
OPNIDN: TRNE F,F.NWL ;Better not have a newline
JRST COMBAD
PUSHJ P,COMRD5 ;Get IF-DOES-NOT-EXIST mode into A
JUMPL BC,COMBAD
CAMN A,[ASCII/ERROR/]
JRST OPNOPT ;ERROR is the default
IFN TNX,[ ;not implemented for ITS yet
CAME A,[ASCII/CREAT/]
];TNX
JRST [ CERR UUO,[Unknown IF-DOES-NOT-EXIST option] ]
TLO F,(F.CRE)
JRST OPNOPT
OPNPRB: MOVEI IDX,MAXIDX ;SPECIAL PROBE INDEX
TRO F,F.PRB ;DOING A PROBE
TRNN F,F.NWL ;IF NO OPTIONS, THAT'S OK
JRST OPNPR0 ;Now process options
OPNFNM: HLLM D,DATSTA(IDX)
IFN ITS,[
PUSHJ P,COMPFN ;PARSE THE FILENAME
SKIPE T,DATSNM(IDX) ;KEEP STICKY DEFAULT DIRECTORY
.SUSET [.SSNAME,,T]
TRNE IDX,1 ;OUTPUT INDEX?
JRST OPNOUT ;YES, HAS TO HAPPEN SOMEWHAT DIFFERENTLY
MOVEI T,.UAI ;ASSUME TEXT MODE
TLNE D,ST.BIN ;UNLESS REALLY BINARY
MOVEI T,.UII
TLNE D,ST.PDT
TRO T,10
TLNE D,ST.INL
TRO T,20
TRNE F,F.PDR ;PROBE-DIRECTORY MODE
JRST [ MOVE TT,[SIXBIT/.FILE./]
MOVEM TT,DATFN1(IDX)
MOVE TT,[SIXBIT/(DIR)/]
MOVEM TT,DATFN2(IDX)
JRST .+1 ]
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW,,T ;Appropriate mode
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,DATFN1(IDX)
%CLIN,,DATFN2(IDX)
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR
.CALL [ SETZ ;GET TRUENAME TO RETURN TO USER
SIXBIT /RFNAME/
%CLIN,,DATCHN(IDX)
%CLOUT,,DATDEV(IDX)
%CLOUT,,DATFN1(IDX)
%CLOUT,,DATFN2(IDX)
%CLOUT+%CLEND,,DATSNM(IDX)]
JFCL ;WELL, IT SHOULDN'T BUT...
TLNN D,ST.BIN ;Don't try to QFASLP for text files
JRST OPNFN0
MOVEI T,1 ;READ THE FIRST WORD OF THE FILE FOR QFASLP
MOVE TT,[444400,,B] ;ONE BYTE INTO B
.CALL [ SETZ
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,TT
%CLIN+%CLEND,,T]
SETZ B, ;HMMM....
CAMN B,[SIXBIT/QFASL/] ;QFASL OR QBIN FILE?
JRST OPNQFA ;YES
TRZ B,77_4 ;ALLOW ANY VERSION BELOW 100
CAMN B,[.BYTE 16. ? 170023 ? 0] ;BIN FILE?
OPNQFA: TROA F,F.QFP ;YES
JRST [TRNN F,F.DEF ;CHARACTERS DEFAULT?
JRST .+1 ;NO
TLZ D,ST.BIN ;YES, NOT BINARY THEN
HLLM D,DATSTA(IDX)
TRNE F,F.PRB
JRST .+1
JRST OPNACF] ;And need to reopen in case it matters
TRNE F,F.PRB ;This a probe?
JRST OPNFN0 ;Yup, don't bother setting the access pointer back
.CALL [ SETZ ;RESET POINTER TO BEGINNING OF FILE
SIXBIT /ACCESS/
%CLIN,,DATCHN(IDX)
%CLIMM+%CLEND,,0]
JRST OPNACF ;ACCESS can fail on things like job devices
JRST OPNFN0
OPNACF: .CALL [ SETZ
SIXBIT /CLOSE/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL ;It can't fail...
MOVEI T,.UAI ;ACCESS failed, so do it the slow way (reopen file)
TLNE D,ST.BIN ;UNLESS REALLY BINARY
MOVEI T,.UII
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW,,T ;Appropriate mode
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,DATFN1(IDX)
%CLIN,,DATFN2(IDX)
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR
JRST OPNFN0
OPNOUT: MOVEI T,.UAO ;ASSUME TEXT MODE
TLNE D,ST.BIN ;UNLESS REALLY BINARY
MOVEI T,.UIO
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD ;Error code
%CLBTW,,T ;Appropriate mode
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,[SIXBIT \_LSPM_\]
%CLIN,,[SIXBIT \OUTPUT\]
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR
SETZM DATLEN(IDX) ;Due to ITS lossage must keep our own length for output files
] ;END IFN ITS
IFN TNX,[
SETZM DATDSP(IDX) ;No delete or rename when closed (so far)
TRNE F,F.PDR
JRST OPNPDR ;PROBE-DIRECTORY
TRNE IDX,1
TLO D,ST.OUT ;COMGJF wants output file
SETZM NOTNEW
TLNE F,(F.SUP\F.APP\F.OVW\F.NEW\F.TRU\F.REN\F.RND)
AOS NOTNEW ;Don't create a new version
TLNE F,(F.APP\F.OVW\F.TRU)
TLNE F,(F.CRE)
CAIA
SETOM NOTNEW ;Must have an old file to append to or write over
PUSHJ P,COMGJF ;Get JFN in AC1
SKIPA
JRST GTRLFL
TLNN F,(F.NEW)
CAIE 1,GJFX27 ;File already exists (new file required)
PUSHJ P,JSYSER ;Error: return it to the user
;We have an existing file
SETOM NOTNEW
PUSHJ P,COMGJG ;Try opening again, as an old file...
PUSHJ P,JSYSER ; Oh well...
TLNE F,(F.APP\F.OVW\F.TRU)
JRST GTRLFL ;Use the old file
MOVE T,1 ;Supersede the old file
HRLI T,DD.SUP+DD.OPN ;Remember that we need to close it first
TLNE F,(F.REN) ;Set flags for rename/delete of old file
TLO T,DD.REN
TLNE F,(F.RND)
TLO T,DD.RND
MOVEM T,DATDSP(IDX)
TLNN D,ST.BIN
SKIPA 2,[070000,,OF%RD+OF%PLN+OF%RTD] ;Input/ASCII/no line numbers!
MOVE 2,[440000,,OF%RD+OF%RTD] ;Input, 36-bit
OPENF ;Open file, to lock it.
ERCAL [ MOVSI T,DD.OPN
ANDCAM T,DATDSP(IDX)
CAIE 1,OPNX30 ;"CAN'T OPEN WHEN ARCHIVED"
CAIN 1,OPNX31 ;"FILE OFFLINE"
POPJ P, ;Ignore these errors and supersede without locking
JRST JSYSER ] ;Probably invalid simultaneous access
HRROI 1,TMPFIL ;Then make a temporary file in the same
HRRZ 2,DATDSP(IDX) ;directory you want the final one...
MOVE 3,[110000,,JS%PAF]
JFNS ;dev:<dir>
HRROI 2,[ASCIZ /-TEMPORARY-FILE-./]
SETZ 3,
SOUT
PUSH P,1
GTAD
MOVE 2,1
POP P,1
MOVEI 3,8.
NOUT
JFCL
HRROI 2,[ASCIZ /.-1/]
SETZ 3,
SOUT
SETZM NOTNEW
HRROI 2,TMPFIL ;and we will write to that one instead.
PUSHJ P,COMGJG
PUSHJ P,JSYSER
GTRLFL: HRRZM 1,DATJFN(IDX) ;JFN for this index
TRNN IDX,1
JRST [TLNN D,ST.BIN
SKIPA 2,[070000,,OF%RD+OF%PLN];Input/ASCII, no line numbers!
MOVE 2,[440000,,OF%RD] ;Input, 36-bit
JRST .+4]
TLNN D,ST.BIN
SKIPA 2,[070000,,OF%WR] ;Output, ASCII
MOVE 2,[440000,,OF%WR] ;Output, 36-bit
TLNE F,(F.APP)
TRC 2,OF%WR+OF%APP ;Open for append instead
TLNE F,(F.OVW)
TRO 2,OF%RD ;Open for both read and write => don't truncate
TLNE D,ST.PDT
TRO 2,OF%PDT
IFN 20X,PUSHJ P,TRYCON
OPENF ;Open the file
ERCAL OPNJER ;Here if some error
SETZM DATLEN(IDX) ;Will keep track of file lengths ourself
TRNN IDX,1 ;Output file, don't do QFASL-P check
TLNN D,ST.BIN ;Don't try to QFASLP for text files
JRST OPNFN0
MOVE 1,DATJFN(IDX)
BIN ;Read byte for QFASL-P
ERJMP OPNNBN ;EOF, not binary
CAMN 2,[SIXBIT/QFASL/] ;QFASL OR QBIN FILE?
JRST OPNQFA ;YES
TRZ 2,77_4 ;ALLOW ANY VERSION BELOW 100
CAMN 2,[.BYTE 16. ? 170023 ? 0] ;BIN FILE?
OPNQFA: TROA F,F.QFP ;YES
JRST OPNNBN ;NO
OPNNB0: TRNE F,F.PRB ;If a probe, no need to set file pointer back
JRST OPNFN0
SETZ 2, ;Set pointer back to beginning of file
SFPTR
JRST OPNACF ;For files that can't be set back, just reopen
JRST OPNFN0
;Analyze OPENF failure
OPNJER:
IFN 20X,[
TRNE F,F.PRB ;If probe, don't care if file is unavailable
JRST OPNJE1 ;SO SKIP THIS STUFF
CAIE 1,OPNX31 ;IS THE FILE OFFLINE?
JRST JSYSER ;NO, SIGNAL THE ERROR
SKIPN RETENA ;ARE AUTOMATIC RETRIEVALS ENABLED?
JRST JSYSER ;NO, SIGNAL THE ERROR
TLNE D,ST.RET ;HAVE WE ALREADY TRIED RETRIEVING THIS FILE?
JRST JSYSER ;YES, SIGNAL THE ERROR
MOVE 1,DATJFN(IDX) ;JFN OF FILE TO BE RETRIEVED
HRRZI 2,.ARRFR ;ARCF RETRIEVAL FUNCTION CODE
MOVE 3,[AR%WAT] ;WE WANNA WAIT FOR THE RETRIEVAL
ARCF% ;RETRIEVE THE FILE
ERJMP .+1 ;IGNORE ANY ERRORS
TLO D,ST.RET ;INDICATE THAT WE HAVE TRIED RETRIEVING FILE
MOVE 1,DATJFN(IDX) ;JFN OF FILE
JRST GTRLFL ;AND RETRY OPENING THE FILE
OPNJE1:
];20X
MOVSI 2,-LERRTB
HLRZ 3,ERRTAB(2)
CAIE 3,(1)
AOBJN 2,.-2
JUMPGE 2,JSYSER
HRRZ 3,ERRTAB(2)
CAIE 3,'NAV
JRST JSYSER
POP P,3 ;Flush return PC
;Fall into OPNNBN
OPNNBN: TRNN F,F.DEF ;CHARACTERS DEFAULT?
JRST OPNNB0 ;NO
TLZ D,ST.BIN ;YES, NOT BINARY THEN
HLLM D,DATSTA(IDX)
TRNE F,F.PRB
JRST OPNNB0
JRST OPNACF ;And need to reopen in case it matters
OPNACF: MOVE 1,DATJFN(IDX)
HRLI 1,(CO%NRJ) ;Don't release the JFN
CLOSF
ERCAL SYSBUG
HRRZS 1
TLNN D,ST.BIN
SKIPA 2,[070000,,OF%RD+OF%PLN] ;Input, ASCII, no line numbers!
MOVE 2,[447400,,OF%RD] ;Input, dump mode
TLNE D,ST.PDT
TRO 2,OF%PDT
OPENF ;Re-open file
ERCAL JSYSER ;Shouldn't happen, but...
];END IFN TOP20
OPNFN0: MOVEI A,[ASCIZ \OPEN \]
PUSHJ P,COMCTL
SKIPE PTCVER
JRST OPNFN3
TRNE F,F.PDR
JRST [ MOVEI BYTE,"1
PUSHJ P,COMCHO
JRST .+2 ]
PUSHJ P,COMVRS
MOVEI BYTE,40
PUSHJ P,COMCHO
OPNFN3:
IFN ITS,[
.CALL [ SETZ
SIXBIT /RFDATE/
%CLIN,,DATCHN(IDX)
%CLOUT+%CLEND,,A]
SETZ A, ;ASSUME 0 IF CALL FAILS
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVEI 2,A ;Return values starting in A
MOVEI 3,1 ;Want one values (last write date)
SETZ A,
RFTAD
ERCAL ERRPDR
] ;END IFN TNX
PUSHJ P,COMDTO ;OUTPUT DATE/TIME FROM A
MOVEI BYTE,40
PUSHJ P,COMCHO
IFN ITS,[
TRNN IDX,1 ;RETURN 0 LENGTH FOR OUTPUT FILES
.CALL [ SETZ
SIXBIT /FILLEN/
%CLIN,,DATCHN(IDX)
%CLOUT+%CLEND,,A] ;SIZE IN 36 BIT BYTES
SETZ A, ;HMM...
] ;END IFN ITS
IFN TNX,[
SETZ A,
TRNE IDX,1
skipge notnew ;GLR output file
caia ; that already exists -- calculate length
JRST OPNFN1 ;Output file, return 0 length
MOVE 1,DATJFN(IDX)
MOVE 2,[2,,.FBBYV] ;Read two words: byte size info, and number of bytes
MOVEI 3,T ;Return info in T and TT
SETZB T,TT
GTFDB
ERCAL ERRPDR
MOVE A,TT
LDB TT,[300600,,T] ;Get byte size
HRLZI T,ST.BIN
TDNN T,DATSTA(IDX) ;If binary mode, do calculation
JRST [CAIN TT,7 ;ASCII mode, was original byte size 7 bits?
JRST OPNFN1 ;Yes, then A contains exact number of bytes
IMULI A,5 ;Else fudge multiplying by number of bytes per word
JRST .+1] ;And do harder calculation
MOVEI T,36.
IDIVI T,(TT) ;And calculate number of bytes per word
ADDI A,-1(T) ;Roundoff correctly
IDIVI A,(T) ;A gets number of words in the file
] ;END IFN TNX
HRLZI T,ST.BIN ;BINARY MODE MULTIPLIES BY APPROPRIATE AMOUNT
TDNN T,DATSTA(IDX)
JRST OPNFN1 ;A HAS ACTUAL LENGTH
IMUL A,DATBPW(IDX)
OPNFN1: MOVEM A,DATLEN(IDX)
PUSHJ P,COMDCO ;OUTPUT IN DECIMAL
MOVEI A,[ASCIZ \ NIL\] ;ASSUME NOT QFASL
TRZE F,F.QFP
MOVEI A,[ASCIZ \ T\]
PUSHJ P,COMSTO ;STRING-OUT THE APPROPRIATE RESPONSE
MOVEI A,[ASCIZ \ NIL\] ;ASSUME NOT CHARACTERS
HRLZI T,ST.BIN
TDNN T,DATSTA(IDX)
MOVEI A,[ASCIZ \ T\]
PUSHJ P,COMSTO
OPNFN2: MOVEI A,[ASCIZ / "/] ;SEND AUTHOR
PUSHJ P,COMSTO
IFN TNX,[
MOVE 1,DATJFN(IDX)
HRLI 1,.GFLWR
HRROI 2,WRITER
GFUST
ERJMP OPNFN4
MOVE A,[440700,,WRITER]
];20X
IFN ITS,[SYSCAL RAUTH,[DATCHN(IDX)
%CLOUT,,WRITER]
JRST OPNFN4
MOVE A,[440600,,WRITER]
];ITS
OPNF2L: ILDB BYTE,A
JUMPE BYTE,OPNFN4
IFN ITS,ADDI BYTE,40 ;Factor for 6bit -> 7bit
CAIE BYTE,""
CAIN BYTE,"/
JRST [PUSH P,BYTE
MOVEI BYTE,"/
PUSHJ P,COMCHO
POP P,BYTE
JRST .+1]
PUSHJ P,COMCHO
JRST OPNF2L
OPNFN4: MOVEI BYTE,""
PUSHJ P,COMCHO
MOVEI BYTE,215 ;A NEWLINE
PUSHJ P,COMCHO
PUSHJ P,COMRFO ;OUTPUT THE REAL FILENAMES
MOVEI BYTE,215
PUSHJ P,COMCHO
TRZN F,F.PRB
JRST OPNFPS ;IF NOT A PROBE, THEN WE ARE DONE
PUSHJ P,COMSND ;PROBE: REPLY QUICKLY
IFN ITS,[
.CALL [ SETZ ;A PROBE, SO CLOSE THE CHANNEL, AS WE ARE DONE WITH IT
SIXBIT /CLOSE/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL ;HMM...OH WELL
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX) ;A probe, so close channel
CLOSF
JRST [ MOVE 1,DATJFN(IDX) ;Might not be open
RLJFN
JFCL
JRST .+1 ]
SETZM DATJFN(IDX)
] ;END IFN TNX
SETZM DATSTA(IDX) ;MAKE SURE WORLD KNOWS CHANNEL IS CLOSED
JRST CTLLOP
OPNFPS: PUSHJ P,BUFALO ;ALLOCATE A BUFFER
MOVEI T,ST%OPN ;STATE IS NOW OPEN
HRRM T,DATSTA(IDX)
HRLZI T,ST.ACT ;CHANNEL IS NOW ACTIVE
IORM T,DATSTA(IDX)
PUSHJ P,COMSND
IFN ITS,[
MOVE T,CHABIT(IDX)
.SUSET [.SIMSK2,,T] ;ENABLE INTERRUPTS ON THE CHAOS CHANNEL
ANDCAM T,SSYDF2 ;Update saved copy of DS2
.SUSET [.SADF2,,T]
.SUSET [.SIIFPIR,,T] ;Start the ball rolling with an interrupt
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
AIC ;Enable interrupts on this channel
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
IIC ;Force interrupt on channel to start ball rolling
] ;END IFN TNX
JRST CTLLOP ;WAIT FOR MORE WORK
IFN ITS,[
;Send version number over
COMVRS: MOVE TT,DATFN2(IDX) ;RETURN FN2 AS VERSION
;SEND THE VERSION NUMBER IN DECIMAL OR -1 IF NOT A NUMBER
;IF PARTIAL NUMBER SEND THAT
MOVEI A,0 ;SET IF ANY DIGITS OUTPUT
COMVR0: MOVEI T,0
LSHC T,6
MOVEI BYTE,40(T)
CAIL BYTE,"0
CAILE BYTE,"9
JRST COMVR1
PUSHJ P,COMCHO
MOVEI A,1
JUMPN TT,COMVR0
COMVR1: JUMPN A,CPOPJ
MOVEI BYTE,"-
PUSHJ P,COMCHO
MOVEI BYTE,"1
PUSHJ P,COMCHO
POPJ P,
;Output filespec to the control stream from DATxxx
COMRFO: MOVE A,DATDEV(IDX) ;DEVICE NAME
CAMN A,[SIXBIT /DSK/] ;If DSK, then send machine name
MOVE A,MACNAM
PUSHJ P,COMSXO
MOVEI A,[ASCIZ \: \] ;COLON TERMINATES DEVICE
PUSHJ P,COMSTO
COMRF2: SKIPN A,DATSNM(IDX) ;THEN SNAME
JRST .+4
PUSHJ P,COMSXO
MOVEI A,[ASCIZ \; \] ;SEMICOLON TERMINATES SNAME
PUSHJ P,COMSTO
TRNE F,F.PDR
POPJ P,
SKIPN A,DATFN1(IDX) ;FIRST FILENAME
JRST [ SKIPN A,DATFN2(IDX)
POPJ P,
MOVEI BYTE,"
PUSHJ P,COMCHO
JRST COMSXO ]
PUSHJ P,COMSXO
SKIPN A,DATFN2(IDX) ;FINALLY, SECOND FILENAME
POPJ P,
MOVEI BYTE,40 ;SPACE ENDS FN1
PUSHJ P,COMCHO
JRST COMSXO ;TAIL RECURSIVE CALL TO SIXBIT OUTPUT
;Version of COMRFO which omits the default device entirely rather than plugging in the host
COMRF1: MOVE A,DATDEV(IDX) ;DEVICE NAME
CAMN A,[SIXBIT /DSK/] ;If DSK, then send nothing
JRST COMRF2
JRST COMRFO
] ;END IFN ITS
IFN TNX,[
COMRFO: SKIPA 3,[111110,,JS%PAF] ;Device, directory, filename, file type, version
COMVRS: MOVE 3,[000010,,0] ;Only return generation
TRNE F,F.PDR
TLZ 3,001110 ;Probe-directory gives only device and directory
HRROI 1,RESBLK ;Output to canonical place
MOVE 2,DATJFN(IDX)
JFNS
ERCAL SYSBUG
JRST COMRES ;Output result block to control packet
;;; 10X/20X PROBE-DIRECTORY
OPNPDR: TRNN F,F.PRB
JRST COMBAD
PUSHJ P,PRSDIR ;Return JFN in 1, directory number in 3
PUSHJ P,OPNPD1 ;Error
HRRZM 1,DATJFN(IDX) ;Really got some JFN, hang onto it
SETZM DATLEN(IDX)
JRST OPNFN0
OPNPD1: CAIE 1,GJFX32 ;Directory empty (no files match specification)
CAIN 1,GJFX19 ;No such file type
JRST POPJ1
CAIE 1,GJFX24 ;Both Tenex and TOPS-20 can give GJFX24 randomly
CAIN 1,GJFX20 ;I think only Tenex gives GJFX20
JRST POPJ1
JRST JSYSER ;Some other error - Complain.
ERRPDR: TRNN F,F.PDR
JRST SYSBUG
POPJ P,
] ;END IFN TNX
;PUSHJ P, for errors that are bugs in the system or in this program
SYSBUG: SETOM SYSBGF ;Set flag and drop into normal routine
;Handle failing .CALLs or JSYSes
FILERR: PUSHJ P,OPNERP ;Setup error packet
PUSHJ P,COMSND ;Send the packet
JRST CTLLOP ;Then wait for more work
IFN TNX,JSYSER=FILERR
OPNERP: MOVEI A,[ASCIZ \ERROR \]
PUSHJ P,COMCTL ;Start off error packet, open failed error code
IFN TNX,[
MOVEI 1,.FHSLF
PUSHJ P,$GETER ;Get last error that happened
PUSHJ P,CTLERR
HRRZM 2,ERRCOD ;The number of the error
];TNX
MOVE D,ERRCOD ;Send 3 letter code for this error
PUSHJ P,ERR3
PUSH P,A ;Save 3-letter code
MOVSS A
PUSHJ P,COMSXO ;Output the 3-letter code
MOVEI A,[ASCIZ \ F \] ;Fatal error
PUSHJ P,COMSTO
PUSHJ P,ERRMSG ;Send the error message
POP P,A ;Restore 3-letter code
CAIE A,'BUG ;If it's a bug, include octal PC
BUGPAT: JRST [ SKIPN DEBUG ;Always include PC if in debugging mode
POPJ P, ;or if BUGPAT is patched to JFCL
JRST .+1 ]
MOVEI A,[ASCIZ \ (at \]
PUSHJ P,COMSTO
HRRZ A,-1(P) ;Caller of FILERR
SUBI A,2 ;Address of errored JSYS or other call
PUSHJ P,COMOCO
MOVEI A,[ASCIZ/ inside FILE server)/]
PUSHJ P,COMSTO
POPJ P,
;Move 3-letter code for error in D to A
ERR3: MOVEI A,'BUG ;Any errors not in our table must be file server bugs
AOSN SYSBGF
POPJ P,
MOVSI TT,-LERRTB ;Search table for appropriate 3 letter code
ERR3A: HLRZ T,ERRTAB(TT)
CAME T,D
AOBJN TT,ERR3A
HRRZ A,ERRTAB(TT)
POPJ P,
;Transmit error message to command packet, D has error code.
IFN ITS,[
ERRMSG: .SUSET [.SPICLR,,[0]] ;ERR device can be used at interrupt level
.CALL [ SETZ ;Now open ERR device to get error message
SIXBIT /OPEN/
%CLBIT,,.UAI
%CLIMM,,ERRCH
%CLIN,,[SIXBIT /ERR/]
%CLIMM,,4
%CLIN+%CLEND,,D]
.LOSE %LSSYS
ERRMS1: .IOT ERRCH,BYTE
JUMPLE BYTE,ERRMS2 ;EOF
CAIN BYTE,15 ;CR turns into Return
MOVEI BYTE,215
CAIL BYTE,40 ;Other control characters are ignored
PUSHJ P,COMCHO
JRST ERRMS1
ERRMS2: .CLOSE ERRCH,
.SUSET [.SPICLR,,[-1]] ;Done with use of any shared resources
POPJ P,
];ITS
IFN TNX,[
ERRMSG: MOVEI 1,.FHSLF ;ERRBUF can be used at interrupt level
DIR
MOVE 2,D
HRLI 2,.FHSLF
HRROI 1,ERRBUF ;Output to canonical place, error in AC2
SETZM ERRBUF
MOVEI 3,ERRLEN-1 ;Maximum number of bytes we can handle
ERSTR
JFCL ;Undefined error number??
JFCL ;Won't fit -- too bad
SKIPE ERRBUF
JRST ERRMS1
HRROI 1,ERRBUF
HRROI 2,[ASCIZ/Undefined system error code /]
MOVEI 3,0
SOUT
HRRZ 2,D
MOVEI 3,8
NOUT
JFCL
ERRMS1:
IFN 10X,[
SETZ 3,
IDPB 3,1 ;Put in null
];IFN 10X
MOVEI A,ERRBUF
PUSHJ P,COMSTO ;Output the error string
MOVEI 1,.FHSLF ;Okay turn interrupts back on
EIR
POPJ P,
];END IFN TNX
;;; Close a data channel
COMCLO: TRNN F,F.FHN ;HAVE A FILE HANDLE?
JRST COMBAD ;NOPE, ERROR
JUMPGE BC,COMBAD ;NO OPTIONS TO THE CLOSE COMMAND
SKIPL T,DATSTA(IDX) ;CHANNEL ACTIVE?
CERR BUG,[Channel not open]
TLNE T,ST.DIR ;Was it a directory listing?
JRST COMCLD
MOVEI A,[ASCIZ \CLOSE \];SUCCESSFUL RESPONSE
PUSHJ P,COMCTL ;SETUP CONTROL PACKET
IFN ITS,[
.CALL [ SETZ
SIXBIT /RFDATE/
%CLIN,,DATCHN(IDX)
%CLOUT+%CLEND,,CLODAT]
SETZM CLODAT ;ASSUME 0 IF CALL FAILS
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVEI 2,A ;Return values starting in A
MOVEI 3,1 ;Want one value (last write date)
RFTAD
ERCAL SYSBUG
MOVEM A,CLODAT
] ;END IFN TNX
TRNE IDX,1 ;Input file?
JRST CLOLE0 ;Nope, output, use calculated length
IFN ITS,[
.CALL [ SETZ
SIXBIT /FILLEN/
%CLIN,,DATCHN(IDX)
%CLOUT+%CLEND,,A] ;SIZE IN 36 BIT BYTES
SETZ A, ;HMM...
] ;END IFN ITS
IFN TNX,[
SETZ A,
MOVE 1,DATJFN(IDX)
MOVE 2,[2,,.FBBYV] ;Read two words: byte size info, and number of bytes
MOVEI 3,T ;Return info in T and TT
GTFDB
ERCAL SYSBUG
MOVE A,TT
LDB TT,[300600,,T] ;Get byte size
HRLZI T,ST.BIN
TDNN T,DATSTA(IDX) ;If binary mode, do calculation
JRST [CAIN TT,7 ;ASCII mode, was original byte size 7 bits?
JRST CLOLE1 ;Yes, then A contains exact number of bytes
JRST .+1] ;And do harder calculation
MOVEI T,36.
IDIVI T,(TT) ;And calculate number of bytes per word
ADDI A,-1(T)
IDIVI A,(T) ;A gets number of words in the file
] ;END IFN TNX
HRLZI T,ST.BIN ;BINARY MODE MULTIPLIES BY 2, TEXT MODE BY 5
TDNN T,DATSTA(IDX)
SKIPA T,[5] ;TEXT: 5
MOVEI T,2 ;BINARY: 2
IMULI A,(T)
JRST CLOLE1
CLOLE0: MOVE A,DATLEN(IDX) ;Actual number of bytes in file
HRLZI T,ST.BIN
TDNN T,DATSTA(IDX) ;If not binary mode then this is the number we want
JRST CLOLE1
MOVE T,DATBPW(IDX)
ADDI A,-1(T) ;In order to round up
IDIVI A,(T) ;Calculate number of words in file
IMULI A,(T) ;Then calculate number of bytes rounded up
; JRST CLOLE1
CLOLE1: MOVEM A,CLOLEN
IFN ITS, PUSHJ P,CLOSIT ;Close the channel
IFN TNX, PUSHJ P,CLONRJ ;Close, but don't release JFN
SKIPE PTCVER
JRST CLOLE2
PUSHJ P,COMVRS
MOVEI BYTE,40
PUSHJ P,COMCHO
CLOLE2: MOVE A,CLODAT
PUSHJ P,COMDTO ;OUTPUT DATE/TIME FROM A
MOVEI BYTE,40
PUSHJ P,COMCHO
MOVE A,CLOLEN ;FILE LENGTH
PUSHJ P,COMDCO ;OUTPUT IN DECIMAL
MOVEI BYTE,40
PUSHJ P,COMCHO
MOVE A,DATRCV(IDX)
PUSHJ P,COMDCO
;; Don't send QFASL info
MOVEI BYTE,215 ;A NEWLINE
PUSHJ P,COMCHO
PUSHJ P,COMRFO ;OUTPUT THE REAL FILENAMES
MOVEI BYTE,215
PUSHJ P,COMCHO
CLOLED: MOVEI A,CPOPJ ;Routine to call in case mark already received
PUSHJ P,COMSSY ;Send/receive synchronous mark
PUSHJ P,COMSND ;Send control response
HRLZI T,ST.SYN ;Wait for mark to go out, or mark to come in
IFN ITS,[ ; (for output, mark supposed to be here already!)
TDNE T,DATSTA(IDX)
.HANG
] ;END IFN ITS
IFN TNX,[
PUSHJ P,RELDJF
;; Nothing winning like .HANG, so use small sleeps
PUSHJ P,$HANG
TDNE T,DATSTA(IDX)
] ;END IFN TNX
SETZM DATSTA(IDX) ;Done with channel now, deactivate it
JRST CTLLOP
IFN TNX,[
$HANG: TIME ;Don't wait forever
IMULI 2,30. ;Just 30 seconds
ADD 1,2
MOVE TT,1
$HANG1: XCT @(P)
CAIA
JRST POPJ1
MOVEI 1,1
DISMS
TIME
CAMG 1,TT
JRST $HANG1
MOVE 1,[441000,,CTLPKO+%CPKDT]
HRROI 2,[ASCIZ/Timed out waiting for synchronous mark on close/]
SETZ 3,
Sout
IDPB 3,1
JRST CTLER1
];TNX
IFN TNX, CLONRJ: TROA F,F.NRJ
CLOSIT:
IFN TNX, TRZ F,F.NRJ
MOVE T,DATSTA(IDX)
TLNE T,ST.DIR ;Directory command?
JRST CLODIR ;Yes, finish up specially
TRNN IDX,1 ;Output file?
JRST CLOSE0 ;Nope, proceed
HRRZ T,DATSTA(IDX)
CAIN T,ST%OPN ;Write out in-core buffer if channel state is OPEN
PUSHJ P,WRIFOR
IFN ITS,[
SKIPN DATFN1(IDX) ;Has file been DELEWO'ed?
JRST CLOSE1 ;Yes, don't RENMWO or set author
.CALL [ SETZ
SIXBIT /RENMWO/
%CLIN,,DATCHN(IDX)
%CLIN,,DATFN1(IDX)
%CLIN+%CLEND,,DATFN2(IDX)]
CERR CRF,[Cannot rename output file to real names]
.CALL [ SETZ
SIXBIT /SAUTH/
%CLIN,,DATCHN(IDX)
%CLIN+%CLEND,,HSNAME]
JFCL ;Unusual, but not fatal
CLOSE1: .CALL [ SETZ ;GET TRUENAME TO RETURN TO USER
SIXBIT /RFNAME/
%CLIN,,DATCHN(IDX)
%CLOUT,,DATDEV(IDX)
%CLOUT,,DATFN1(IDX)
%CLOUT,,DATFN2(IDX)
%CLOUT+%CLEND,,DATSNM(IDX)]
JFCL ;WELL, IT SHOULDN'T BUT...
] ;END IFN ITS
IFN TNX,[
CLOSE0: MOVE 1,DATJFN(IDX)
HRLI 1,(CO%NRJ) ;Close file, but keep around JFN
MOVSI TT,DD.ABT
TDNE TT,DATDSP(IDX)
TLO 1,(CZ%ABT) ;If going to delete, close in abort mode
CLOSF
ERCAL SYSBUG ;Ain't much else we can do...
TDNE TT,DATDSP(IDX) ;Delete?
JRST [MOVE 1,DATJFN(IDX) ; Yes
HRLI 1,(DF%NRJ)
DELF
ERCAL JSYSER
PUSHJ P,RELRJF ;Not going to rename to real name
JRST CLOSE2]
MOVE 1,DATDSP(IDX)
TLNE 1,DD.OPN ;Before we can RNAMF this temporary
JRST [ HRLI 1,(CO%NRJ) ;file, it must be closed.
CLOSF
ERCAL SYSBUG
JRST .+1 ]
MOVE TT,DATSTA(IDX)
HRRZ 1,DATFBS(IDX)
CAIN 1,36. ;Wants fullword?
JRST CLSIT0 ;Yes, no conversison necessary
TLNE TT,ST.BIN ;Is this a binary...
TRNN IDX,1 ; ... WRITE operation?
JRST CLSIT0 ;No, so don't hack the file size
MOVE T,DATLEN(IDX) ;Number of transmission bytes in file
MOVE 3,DATBPW(IDX) ;(do it this way in case lhs is used)
IDIVI T,(3) ;T=number of words
MOVE 3,DATBYT(IDX)
IMULI TT,(3) ;TT=number of bits left over
MOVEI 2,36. ;Convert it all to the file byte size
IDIVI 2,(1)
IMULI T,(2)
MOVE 2,TT
ADDI 2,-1(1)
IDIVI 2,(1)
ADD T,2
HRRZ 1,DATJFN(IDX) ;Set the byte count
HRLI 1,.FBSIZ\(CF%NUD) ;(minimize the non-atomicity...)
SETO 2,
MOVE 3,T
CHFDB
ERCAL SYSBUG
HRLI 1,.FBBYV ;And now the byte size
MOVSI 2,(FB%BSZ)
SETZ 3,
MOVE T,DATFBS(IDX)
DPB T,[.BP FB%BSZ,3]
CHFDB
ERCAL SYSBUG
CLSIT0:
MOVE TT,DATDSP(IDX)
TLNN TT,DD.REN\DD.RND ;Get rid of existing file?
JRST CLOSE1
HRROI 1,RESBLK ;Get a name to rename it to
HRRZ 2,TT
MOVE 3,[111000,,JS%PAF]
JFNS ;dev:<dir>name
ERCAL SYSBUG
HRROI 2,[ASCIZ /.REPLACED-FILE/]
SETZ 3,
SOUT
MOVE 1,[GJ%FOU+GJ%NEW+GJ%SHT+.GJDEF] ;Setup flags to GTJFN
HRROI 2,RESBLK
GTJFN
ERCAL SYSBUG
PUSH P,1
HRROI 1,RESBLK ;Make a copy of the JFN so we can rename it
HRRZ 2,TT
MOVE 3,[111110,,JS%PAF] ;Device, directory, filename, file type, version
JFNS
ERCAL SYSBUG
MOVE 1,[GJ%OLD+GJ%SHT+.GJDEF] ;Setup flags to GTJFN
HRROI 2,RESBLK
GTJFN
ERCAL SYSBUG
POP P,2
RNAMF
ERCAL SYSBUG
MOVE 1,2
HRLI 1,(DF%NRJ)
TLNE TT,DD.RND
DELF
ERCAL SYSBUG
HRRZS 1
RLJFN
JFCL
CLOSE1: MOVSI TT,DD.SUP
TDNN TT,DATDSP(IDX) ;Rename over existing file?
JRST CLOSE2 ; No.
MOVE 1,DATJFN(IDX) ;Old name...
HRRZ 2,DATDSP(IDX) ;...New name
RNAMF
ERCAL JSYSER
HRRZ 1,DATDSP(IDX)
MOVEM 1,DATJFN(IDX)
CLOSE2: SETZM DATDSP(IDX) ;Mark JFN in RH as released.
TRNN F,F.NRJ
PUSHJ P,RELDJF
] ;END IFN TNX
IFN ITS, CLOSE0:
CLODON: MOVE T,DATSTA(IDX) ;Get channel status
IFN TNX,[
IFN $$SUBM,[
TLNN T,ST.SUB
JRST SUBM2
SKIPE A,QSRPID
JRST SUBM1
SUBM0: MOVEI 1,3 ;Get QUASAR's PID.
MOVEI 2,QUTILB
MUTIL
JRST [MOVEI A,^D3000 ;Sleep for three seconds
DISMS
JRST SUBM0]
MOVE TT,QSRPID
MOVEM TT,MSENDB+2 ;Save QUASAR's pid in MSEND block.
SUBM1: MOVE TT,[QPBLK,,QSRLOC] ;Blit in the args
BLT TT,QSRLOC+19
HRROI 1,QSRLOC+8.
MOVE 2,DATJFN(IDX)
MOVE 3,[111110,,JS%PAF]
JFNS
HRRZ 1,1 ;A has last word written.
SUBI 1,QSRLOC+6 ;Number of words plus 1.
HRLM 1,QSRLOC+7 ;Length of block#2
ADDI 1,7
HRLM 1,QSRLOC ;Total length of block.
SKIPN YERPID
SKIPA 1,[IP%CFV\IP%CPD] ;Page-long and make us a PID.
MOVEI 1,IP%CFV ;Just page-long send
MOVEM 1,MSENDB+.IPCFL
MOVEI 1,4
MOVEI 2,MSENDB
MSEND
CERR BUG,[Can't submit file]
SUBM2:
];$$SUBM
];TNX
MOVEI TT,(T)
CAIN TT,ST%OPN ;Was the channel open?
HRRI T,ST%CLO ;Yes, then close it
MOVEM T,DATSTA(IDX)
PUSHJ P,BUFDAL ;DEALLOCATE THE CORE BUFFER
IFN ITS,[
.CALL [ SETZ
SIXBIT /CLOSE/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL ;HMMMM...."I GUESS WE'LL SURVIVE"
] ;END IFN ITS
POPJ P,
IFN TNX,[
RELDJF: SKIPN 1,DATJFN(IDX) ;Release data-file JFN, and mark as such.
POPJ P,
HRLI 1,(CZ%ABT) ;Try closing since RLJFN fails if it's open
CLOSF
JFCL
RELDJ1: MOVE 1,DATJFN(IDX) ;Here when not open, to not clobber error code
RLJFN
JFCL
SETZM DATJFN(IDX)
POPJ P,
RELRJF: HRRZ 1,DATDSP(IDX)
JUMPE 1,CPOPJ
HRLI 1,(CZ%ABT)
CLOSF
JFCL
RELRJ1: HRRZ 1,DATDSP(IDX) ;Here when not open, to not clobber error code
JUMPE 1,CPOPJ
RLJFN
JFCL
SETZM DATDSP(IDX)
POPJ P,
];TNX
;;; FILEPOS: for input files only
COMFIL: TRNN F,F.NWL ;Can't have a newline
TRNN F,F.FHN ;And must have a file handle
JRST COMBAD
SKIPGE DATSTA(IDX) ;IDX must be active
caia ;GLR And ok if it is write
CERR BUG,[Illegal file handle for FILEPOS]
trne idx,1 ;GLR if output,
pushj p,wrifor ;GLR send out the leftover characters in buffer
JUMPL BC,COMBAD ;Also need an argument
PUSHJ P,COMDCI ;Read the arg in decimal
JUMPGE BC,COMBAD ;Better be the end
HRLZI T,ST.BIN ;Is this a binary channel?
TDNN T,DATSTA(IDX)
JRST FILNBN ;Nope, filepos is in A
IDIV A,DATBPW(IDX) ;A is number of words in, B is number of bytes after that
DPB B,[360600,,A] ;Need to save this for interrupt routine
FILNBN: MOVEM A,DATSYN(IDX) ;Location reserved for synchronous routines
MOVEI A,FILSYN ;Routine to call
PUSHJ P,COMSSY ;Setup for the sync mark
MOVEI A,[ASCIZ \FILEPOS\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
HRLZI T,ST.SYN ;Wait for mark to go out
IFN ITS,[
TDNE T,DATSTA(IDX)
.HANG
] ;END IFN ITS
IFN TNX,[
;; Nothing winning like .HANG, so use small sleeps
PUSHJ P,$HANG
TDNE T,DATSTA(IDX)
] ;END IFN TNX
JRST CTLLOP ;Ok, all done, go back for more
;;; Here after sync mark gets sent. Called from interrupt and main program level
FILSYN: MOVE T,DATSYN(IDX) ;Get word (byte in text mode) address to ACCESS to
TLZ T,770000 ;Clear sub-word
IFN ITS,[
.CALL [ SETZ
SIXBIT /ACCESS/
%CLIN,,DATCHN(IDX)
%CLIN+%CLEND,,T]
AERR CPOPJ,WKF,[Cannot set pointer]
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,T ;Where pointer is to get set to
SFPTR
AERR CPOPJ,FOR,[Cannot set pointer] ;COULD BE WKF ALSO---
] ;END IFN TNX
SETZM DATBPT(IDX) ;No state is left
SETZM DATBCT(IDX)
SETZM DATLWD(IDX)
HRRI A,ST%OPN ;Channel is now in open state
TRNE IDX,1 ;Output channel?
POPJ P, ;Yes, then we are done
LDB T,[360600,,DATSYN(IDX)] ;Get number of bytes into first word
JUMPE T,CPOPJ ;If none, then just return.
PUSHJ P,REABUF ;Else read in the next bufferful
SKIPG T,DATBCT(IDX) ;Any bytes to hack?
POPJ P, ;Nope, just return, EOF will be sent next interrupt
LDB TT,[360600,,DATSYN(IDX)]
SUBI T,(TT) ;Calculate number of bytes that will remain in buffer
JUMPLE T,FILSY0 ;If it's gonna be 0 or negative, then EOF
MOVEM T,DATBCT(IDX) ;Else this is the new count
IBP DATBPT(IDX) ;Step the pointer to the appropriate spot
SOJG TT,.-1
POPJ P,
FILSY0: SETZM DATBPT(IDX)
SETZM DATBCT(IDX)
SETZM DATLWD(IDX)
POPJ P,
;;; SET-BYTE-SIZE <new-byte-size> <new-filepos-in-terms-of-old-byte-size-for-input-files>
COMSBS: JUMPL BC,COMBAD ;End of packet, losing format
TRZE F,F.NWL ;Can't have new line either
JRST COMBAD
SKIPGE T,DATSTA(IDX) ;This channel active?
TLNN T,ST.BIN ;And a binary channel?
CERR WKF,[SET-BYTE-SIZE only allowed for binary file]
PUSHJ P,COMDCI ;Read new byte size in decimal
JUMPL BC,COMBAD
TRZE F,F.NWL
JRST COMBAD
HRLM A,DATBYT(IDX) ;Remember new byte size
TRNE IDX,1 ;Need to set a filepos?
JRST SBSNFP ;Nope, ignore rest of packet
PUSHJ P,COMDCI ;Else read the filepos
IDIV A,DATBPW(IDX) ;A is number of words in, B is number of bytes after that
; of current position in file
DPB B,[360600,,A] ;Need to save this for interrupt routine
MOVEM A,DATSYN(IDX)
SBSNFP: MOVEI A,SBSSYN ;Routine to call
PUSHJ P,COMSSY ;Setup for the sync mark
MOVEI A,[ASCIZ \SET-BYTE-SIZE\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
HRLZI T,ST.SYN ;Wait for mark to go out
IFN ITS,[
TDNE T,DATSTA(IDX)
.HANG
] ;END IFN ITS
IFN TNX,[
;; Nothing winning like .HANG, so use small sleeps
PUSHJ P,$HANG
TDNE T,DATSTA(IDX)
] ;END IFN TNX
JRST CTLLOP ;Ok, all done, go back for more
;;; Here upon receipt of synchronous mark
SBSSYN: HLRZS TT,DATBYT(IDX) ;Set up new byte size as current byte size
TRNN IDX,1 ;If reading from file do filepos and return
JRST FILSYN
SKIPE DATBPT(IDX) ;If a byte pointer is around, change its byte size
DPB TT,[360600,,DATBPT(IDX)]
HRRI A,ST%OPN ;Channel is now in open state
MOVEI T,36. ;Calculate and remember number of bytes per word
IDIVI T,(TT)
MOVEM T,DATBPW(IDX)
POPJ P, ;Then we are done
;;; DELETE, RENAME and other sundry file operations
;;; DELETE
COMDEL: TRNN F,F.FHN ;Did we have a file handle?
JRST DELFIL ;Nope, filename must be specified
JUMPGE BC,COMBAD ;Must be end of command string here
IFN ITS,[
.CALL [ SETZ
SIXBIT /DELEWO/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL ;Can't fail, can it??
SETZM DATFN1(IDX) ;Flag file as deleted
] ;END IFN ITS
IFN TNX,[
MOVSI TT,DD.ABT
IORM TT,DATDSP(IDX) ;Flag for deletion later
] ;END IFN TNX
MOVEI A,[ASCIZ \DELETE\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
JRST CTLLOP
DELFIL: TRZN F,F.NWL ;Newline?
JRST COMBAD ;Nope, bad command format
MOVEI IDX,MAXIDX ;Use the temporary channel for this
IFN ITS,[
PUSHJ P,COMPFN ;Parse the filename to be deleted
TRZN F,F.NWL ;Check for correct format
JRST COMBAD
SKIPE T,DATSNM(IDX) ;Keep sticky default directory
.SUSET [.SSNAME,,T]
.CALL [ SETZ
SIXBIT /DELETE/
%CLERR,,ERRCOD ;Error code
%CLIN,,DATDEV(IDX)
%CLIN,,DATFN1(IDX)
%CLIN,,DATFN2(IDX)
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR ;File error, tell about it
] ;END IFN ITS
IFN TNX,[
SETZ D, ;COMGJF wants input file
PUSHJ P,COMGJF ;Get JFN
PUSHJ P,JSYSER ;Error, return it to the user
HRRZM 1,DATJFN(IDX) ;Save JFN
IFN 20X,PUSHJ P,TRYCON
DELF
ERCAL JSYSER
] ;END IFN TNX
MOVEI A,[ASCIZ \DELETE\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
JRST CTLLOP
;;; RENAME
COMREN: TRZN F,F.NWL ;Both formats require newline
JRST COMBAD
TRNN F,F.FHN ;Use an open file?
JRST RENFIL ;Nope, need two filenames
IFN ITS,[
PUSH P,DATDEV(IDX)
PUSH P,DATSNM(IDX)
PUSHJ P,COMPFN ;Parse the filename
TRZN F,F.NWL ;Must be terminated by newline
JRST COMBAD
POP P,B ;Old directory
POP P,A ;Old device
PUSHJ P,RNMCHK
TRNE IDX,1 ;An output file?
JRST RENCOM ;Yes, using a temp name anyway, just proceed
.CALL [ SETZ
SIXBIT /RENMWO/
%CLERR,,ERRCOD ;Error code
%CLIN,,DATCHN(IDX)
%CLIN,,DATFN1(IDX)
%CLIN+%CLEND,,DATFN2(IDX)]
PUSHJ P,FILERR
MOVEI A,[ASCIZ \RENAME\]
PUSHJ P,COMCTL
MOVEI BYTE,215 ;A NEWLINE
PUSHJ P,COMCHO
.CALL [ SETZ ;GET TRUENAME TO RETURN TO USER
SIXBIT /RFNAME/
%CLIN,,DATCHN(IDX)
%CLOUT,,DATDEV(IDX)
%CLOUT,,DATFN1(IDX)
%CLOUT,,DATFN2(IDX)
%CLOUT+%CLEND,,DATSNM(IDX)]
JFCL ;WELL, IT SHOULDN'T BUT...
PUSHJ P,COMRFO ;OUTPUT THE REAL FILENAMES
PUSHJ P,COMSND
JRST CTLLOP
;Here, the real filenames are not known yet.
RENCOM: MOVEI A,[ASCIZ \RENAME\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
JRST CTLLOP
] ;END IFN ITS
IFN TNX,[
HRLZI D,ST.OUT ;COMGJF wants output file
SETZM NOTNEW
PUSHJ P,COMGJF ;Get a JFN for the file
PUSHJ P,JSYSER
MOVE 2,DATDSP(IDX) ;2 gets "current" (may not have that name yet really)
TLNN 2,DD.SUP
MOVE 2,DATJFN(IDX)
PUSHJ P,RENTNM ;Build return packet
HRLI 1,DD.SUP
PUSH P,1 ;Save new name
PUSHJ P,RELRJF ;Dispose of old DATDSP file name
POP P,DATDSP(IDX) ;Defer processing until file gets closed
PUSHJ P,COMSND
JRST CTLLOP
];END IFN TNX
RENFIL: MOVEI IDX,MAXIDX ;A phony IDX to use
IFN ITS,[
PUSHJ P,COMPFN ;Parse the from filename
TRZN F,F.NWL ;Must have trailing newline
JRST COMBAD
SKIPE T,DATSNM(IDX) ;Keep sticky default directory
.SUSET [.SSNAME,,T]
IRPS WHAT,,[DATDEV,DATFN1,DATFN2,DATSNM]
PUSH P,WHAT(IDX)
TERMIN
PUSHJ P,COMPFN ;Parse the next filespec
TRZN F,F.NWL
JRST COMBAD
MOVE A,-3(P) ;DATDEV
MOVE B,0(P) ;DATSNM
PUSHJ P,RNMCHK
.CALL [ SETZ
SIXBIT /RENAME/
%CLERR,,ERRCOD
%CLIN,,A
%CLIN,,-2(P)
%CLIN,,-1(P)
%CLIN,,B
%CLIN,,DATFN1(IDX)
%CLIN+%CLEND,,DATFN2(IDX)]
PUSHJ P,FILERR ;Report file error
SUB P,[4,,4] ;Not really necessary, but get rid of pushed cruft
JRST RENCOM
RNMCHK: MOVE T,DATDEV(IDX) ;Both devices must be the same.
CAMN T,MACNAM
MOVE T,[SIXBIT/DSK/]
CAMN A,MACNAM
MOVE A,[SIXBIT/DSK/]
CAME A,T
JRST [ CERR RAD,[Cannot rename across devices] ]
SKIPN B
.SUSET [.RSNAME,,B]
SKIPN DATSNM(IDX)
MOVEM B,DATSNM(IDX) ;dir of second file defaults to the first one's.
CAMN B,DATSNM(IDX)
POPJ P, ;They must also be the same.
CERR RAD,[Cannot rename across directories]
] ;END IFN ITS
IFN TNX,[
SETZ D, ;Get input file first
PUSHJ P,COMGJF ;Get JFN for file
PUSHJ P,JSYSER ;Can't get JFN, so return
MOVEM 1,DATDSP(IDX) ;Save source JFN
TLO D,ST.OUT ;Next file is 'output' file
SETZM NOTNEW
PUSHJ P,COMGJF
PUSHJ P,RELINF ;Can't get output JFN, so release input JFN (doesn't return)
MOVE 2,DATDSP(IDX)
PUSHJ P,RENTNM ;Build response packet presuming success
MOVE 2,1
MOVE C,1 ;Remember target in case of error
MOVE 1,DATDSP(IDX)
IFN 20X,[
MOVEM 1,DATJFN(IDX) ;Implicit arg to TRYCON
PUSHJ P,TRYCON
];20X
RNAMF
ERCAL [MOVE 1,C
RLJFN
JFCL
IFN 20X,SETZM DATJFN(IDX)
JRST RELINF]
MOVE 1,C
RLJFN
JFCL
IFN 20X,SETZM DATJFN(IDX)
PUSHJ P,COMSND
JRST CTLLOP
RELINF: PUSHJ P,RELRJ1 ;Release DATDSP(IDX)
JRST JSYSER
;Store target truename from JFN in 1, and source truename from 2
;into success packet, to be sent later if we succeed. Preserves 1.
RENTNM: PUSH P,1
PUSH P,2
MOVEI A,[ASCIZ \RENAME\]
PUSHJ P,COMCTL
MOVEI BYTE,215
PUSHJ P,COMCHO
HRROI 1,RESBLK ;Target truename
MOVE 2,-1(P)
MOVE 3,[111110,,JS%PAF] ;Device, directory, filename, file type, version
JFNS
ERCAL SYSBUG
PUSHJ P,COMRES
MOVEI BYTE,215
PUSHJ P,COMCHO
HRROI 1,RESBLK ;Source truename
POP P,2
MOVE 3,[111110,,JS%PAF] ;Device, directory, filename, file type, version
JFNS
ERCAL SYSBUG
PUSHJ P,COMRES
POP1J: POP P,1
POPJ P,
];END IFN TNX
;;; CONTINUE command. Continue processing after a recoverable asynchronous error
COMCON: JUMPGE BC,COMBAD ;Better not have any more stuff
TRNN F,F.FHN ;Need a file handle
JRST COMBAD
SKIPL A,DATSTA(IDX) ;Channel must be active
CONCCC: CERR BUG,[Channel cannot continue]
MOVEI T,ST%ASY ;Must be in async mark state
CAIN T,(A)
TLNE A,ST.UNC ;And must be continuable
JRST CONCCC
HRRI A,ST%OPN ;Ok, so fix up
MOVEM A,DATSTA(IDX)
MOVEI A,[ASCIZ \CONTINUE\]
PUSHJ P,COMCTL ;Send completion response
PUSHJ P,COMSND
IFN ITS,[
.CALL [ SETZ ;Continue the interrupted I/O operation
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,DATBPT(IDX)
%CLIN+%CLEND,,DATBCT(IDX)]
JRST CONERR ;Another IOC error, didn't really fix the problem
.SUSET [.SPICLR,,[0]] ;Don't allow interrupts, and the continuation better not
; do anything that causes them!
] ;END IFN ITS
IFN TNX,[
PUSHJ P,DOSIO ;Continue I/O operation
JRST CONERR
MOVEI 1,.FHSLF
DIR
] ;END IFN TNX
MOVE A,DATSTA(IDX)
PUSHJ P,@DATICN(IDX)
MOVEM A,DATSTA(IDX)
IFN ITS,[
.SUSET [.SPICLR,,[-1]]
MOVE T,CHABIT(IDX)
ANDCAM T,SSYDF2 ;Update saved copy of DF2 (can't hurt even if not masked)
TRNE IDX,1 ;Undefer interrupts if necessary
.SUSET [.SADF2,,T]
.SUSET [.SIIFPIR,,T] ;Cause interrupt to start the ball rolling
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF ;Turn interrupt system back on
EIR
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
AIC ;Reenable interrupts on this channel
IIC ;Force interrupt on channel to start ball rolling
] ;END IFN TNX
JRST CTLLOP ;Then done
CONERR:
IFN ITS,[
.SUSET [.SPICLR,,[0]] ;Using shared resources, prevent timing screws
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
DIR
] ;END IFN TNX
PUSH P,DATICN(IDX) ;Save important stuff over the IOC error emission
MOVE A,DATSTA(IDX) ;ICCERR wants status in A
MOVEI D,DATICN-1(IDX) ;And continuation in c(1(D))
PUSHJ P,[PUSHJ P,ICCERR] ;*K*L*U*D*G*E*
POP P,DATICN(IDX)
IFN ITS,[
.SUSET [.SPICLR,,[-1]]
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
EIR
] ;END IFN TNX
JRST CTLLOP ;Then done
IFN TNX,[
DOSIO: MOVE 1,DATJFN(IDX)
MOVE 2,DATBPT(IDX)
MOVN 3,DATBCT(IDX)
JUMPE 3,DOSIO1
TRNE IDX,1
JRST DOSIOO ;Output
SIN
ERJMP .+1
DOSIO1: PUSHJ P,ITSBP ;Turn BP in AC2 into an ITS standard byte pointer
MOVEM 2,DATBPT(IDX)
MOVNM 3,DATBCT(IDX)
SKIPN 3 ;Means we didn't make it all out
AOS (P)
POPJ P,
DOSIOO: SOUT
ERJMP DOSIO1
JRST DOSIO1
ITSBP: PUSH P,T
LDB T,[360600,,2] ;PP field of BP in AC2
JUMPN T,ITSBP0 ;Some bits left, so is ok
MOVEI T,44 ;Make agree with ITS -- point off left of next word
DPB T,[360600,,2]
AOS 2
ITSBP0: POP P,T
POPJ P,
] ;END IFN TNX
;;; Directory command
DATNDR==:DATBYT ;Next directory, 0 = start, -1 = done
IFN ITS,[
DATDRP==:DATBPW ;File being processed (index to UFD)
.INSRT SYSTEM;FSDEFS
] ;END IFN ITS
IFN TNX,[
DATDRN==:DATBPW ;Directory number being processed
]
COMPRO: TRZA F,F.DIR
COMDIR: TRO F,F.DIR
SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
TRNN F,F.FHN ;Must have file handle
CERR BUG,[Must have a file handle]
TRNE IDX,1 ;Input index?
CERR BUG,[Channel wrong direction]
SKIPGE DATSTA(IDX)
PUSHJ P,CLOSIT ;Close open channel
SETZM DATSTA(IDX)
MOVSI D,ST.DIR
TRZN F,F.DIR
TLO D,ST.PRO
DIROPT: TRNE F,F.NWL ;End of options? Or no file handle in PROPERTIES
JRST DIRFNM
TLNE D,ST.PRO
JRST COMPR1 ;PROPERTIES command with a file handle
PUSHJ P,COMRD5 ;Get token
JUMPL BC,COMBAD
DIROLP: MOVEI T,DIRLEN-1
DIROL1: CAME A,DIRTAB(T)
SOJGE T,DIROL1
JUMPL T,[CERR UUO,[Unknown DIRECTORY option]]
XCT DIRACT(T)
JRST COMBAD
JRST DIROPT
DIRTAB: ASCII \DELET\ ;Allow deleted files as well
ASCII \FAST\
ASCII \NO-EX\
ASCII \DIREC\
Ascii \SORTE\
DIRLEN==.-DIRTAB
DIRACT: TLOA D,ST.DEL
TLOA D,ST.FST
SKIPA
TLOA D,ST.ALD
SKIPA
;PROPERTIES command with a file handle
COMPR1: PUSHJ P,COMRD5 ;Get file handle
JFCL
JUMPGE BC,COMBAD ;Shouldn't have anything left over
MOVEI B,MAXIDX-1 ;LOOP OVER ALL INDICES
COMPR2: CAMN A,DATFHN(B) ;MATCH?
JRST COMPR3 ;YUP
SOJGE B,COMPR2
CERR BUG,[Unknown file handle argument to PROPERTIES]
COMPR3:
IFN TNX,[
MOVE 1,DATJFN(B)
TLZ D,ST.NOK
JRST SVDFLG
;PROPERTIES command with a file name joins
COMPR4: TLO D,ST.DEL\ST.NOK ;ST.NOK means we have a JFN to get rid of
PUSHJ P,COMGJF ;Get JFN in AC1
PUSHJ P,JSYSER
JRST SVDFLG
];TNX
IFN ITS,[
MOVE B,DATCHN(B)
.CALL [ SETZ ;Need device and directory names
SIXBIT /RFNAME/
%CLIN,,B
%CLOUT,,DATDEV(IDX)
%CLOUT,,DATFN1(IDX)
%CLOUT,,DATFN2(IDX)
%CLOUT+%CLEND,,DATSNM(IDX)]
PUSHJ P,SYSBUG
JRST COMPR5
;PROPERTIES command with a file name joins
COMPR4: .CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW,,.UAI+30 ;preserve dates, inhibit links
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,DATFN1(IDX)
%CLIN,,DATFN2(IDX)
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR
MOVE B,DATCHN(IDX)
COMPR5: MOVEM B,DATFN1(IDX) ;Save channel number in weird place
JRST COMPR6
];ITS
DIRFNM:
IFN ITS,[
TLNN D,ST.PRO
SETOM STARF2 ;We want * for default FN2
PUSHJ P,COMPFN ;Parse the filename spec
SETZM STARF2
SKIPE T,DATSNM(IDX) ;KEEP STICKY DEFAULT DIRECTORY
.SUSET [.SSNAME,,T]
TLNE D,ST.PRO
JRST COMPR4
MOVSI T,(SIXBIT/*/)
SKIPN DATFN1(IDX)
MOVEM T,DATFN1(IDX)
COMPR6: PUSHJ P,LCKDIR ;Get DIRLCK
PUSHJ P,GETMFD ;Read in the MFD
PUSHJ P,[ HLRZ A,DATDEV(IDX) ;Archive devices just say they cannot work.
TRZ A,77
CAIE A,(SIXBIT /AR/)
JRST [ SETZM DIRLCK ? JRST FILERR ]
MOVEI A,[ASCIZ \ERROR \]
PUSHJ P,COMCTL ;Start off error packet, open failed error code
MOVEI A,[ASCIZ \WKF F CANNOT LIST ARCHIVE DEVICE\]
PUSHJ P,COMSTO
PUSHJ P,COMSND
JRST CTLLOP ]
;The following might be nice, but the directory format of archives is evidently
;not 100% compatible since we get an MPV trying to look at the descriptors.
;So we give an error if we try to take the directory of an archive.
;Note that it is necessary to read in the MFD even if the sname is not wildcarded,
;since the MFD is needed to decode file authors.
IFN 0,[ PUSHJ P,[ HLRZ A,DATDEV(IDX) ;Kludge around for archives
TRZ A,77
CAIE A,(SIXBIT/AR/)
JRST [ SETZM DIRLCK ? JRST FILERR ] ;Device doesn't exist?
PUSH P,DATDEV(IDX)
MOVSI A,'DSK
MOVEM A,DATDEV(IDX)
PUSHJ P,GETMFD
JRST [ POP P,DATDEV(IDX) ? SETZM DIRLCK ? JRST FILERR ]
POP P,DATDEV(IDX)
POPJ P, ]
];IFN 0
;; Allocate space for directory mapping
MOVEI T,DIRBUF/2000
PUSHJ P,PAGALO
SETZM DATDRP(IDX)
] ;END IFN ITS
IFN TNX,[
TLNE D,ST.PRO
JRST COMPR4
TLNE D,ST.ALD
JRST [ TLO D,ST.PON ;Do parse only
SETZM DATDRN(IDX)
JRST .+1]
PUSHJ P,COMGDJ ;Get directory JFN, with wildcards
JRST DIREMP
SVDFLG: MOVEM 1,DATJFN(IDX) ;Save it,
DRNFIL:
] ;END IFN TNX
IFN ITS,[
PUSHJ P,DIRSI2 ;See if dir exists.
PUSHJ P,FILERR ;Failure.
];ITS
SETZM DATNDR(IDX) ;Success, or hard to tell. Will start listing next time around
HLLM D,DATSTA(IDX) ;Save status bits
MOVEI A,[ASCIZ \DIRECTORY\]
TLNE D,ST.PRO
MOVEI A,[ASCIZ \PROPERTIES\]
PUSHJ P,COMCTL
JRST OPNFPS ;Finish up like open
IFN TNX,[
;GTJFN error code in 1
DIREMP: SETZM DATJFN(IDX) ;Make sure cleared out from last time.
CAIE 1,GJFX32 ;Directory empty (no files match specification)
CAIN 1,GJFX19 ;No such file type
JRST DRNFIL ;Yes, give directory stream with no files in it
CAIE 1,GJFX24 ;Both Tenex and TOPS-20 can give GJFX24 randomly
CAIN 1,GJFX20 ;I think only Tenex gives GJFX20
JRST DRNFIL
PUSHJ P,JSYSER ;Some other error - Complain.
];TNX
IFN ITS,[
;Skip if requesting either multiple directories or a single directory which exists.
;Do not skip if requesting a single directory which does not exist.
;If requesting a single directory which exists,
;we also read it in, so you can omit doing so later.
DIRSI2: MOVE TT,DATSNM(IDX) ;Get directory requested
DIRSI0: JUMPE TT,DIRSI1 ;Simple case, no directory wildcards
SETZ T,
LSHC T,6
CAIE T,'* ;A wildcard specifier?
JRST DIRSI0
JRST POPJ1
;; Simple case, only one directory
;; Try to read it in now; if we fail, report an error now.
DIRSI1: MOVE A,DATSNM(IDX)
MOVSI T,ST.ALD
TDNE T,DATSTA(IDX) ;Just wants directory names, not contents, => skip.
JRST POPJ1
PUSHJ P,GETUF1
POPJ P,
JRST POPJ1
];ITS
;;; Come here from REABUF when need some more input from a directory listing
;;; T has byte pointer to store into, TT has byte count
REDRBF: PUSH P,A
PUSH P,B ;Save some ac's
PUSH P,BC
PUSH P,BP
;; Directory loop, try to fill buffer with all info on one file, if we run out of room,
;; we back up the pointer to before the current file and return with that
MOVE BP,T
MOVE BC,TT
MOVE D,DATSTA(IDX)
SKIPN DATNDR(IDX) ;First time?
PUSHJ P,DIRHED ;Yes, print header
PUSH P,BP ;Save byte pointer
PUSH P,BC ;and counter
MOVEM P,DIRPDL ;Save stack pointer
REDRB0: PUSHJ P,DIRFIL ;Do one file
JRST REDBF1 ;No file to do
MOVEM BP,-1(P) ;Save updated byte pointer
MOVEM BC,(P) ;and count
JRST REDRB0
;; Done filling buffer, restore state and return
REDBF1: MOVE P,DIRPDL
POP P,TT ;Restore byte count
POP P,T ;and pointer
POP P,BP
POP P,BC
POP P,B
POP P,A
JRST REABF3 ;Return to main body of code
;;; Come here from COMCLO for directory channel
COMCLD: PUSHJ P,CLOSIT
MOVEI A,[ASCIZ \CLOSE\]
PUSHJ P,COMCTL
JRST CLOLED
;;; Come here from CLOSIT when done with a directory channel
CLODIR:
IFN ITS,[
MOVE TT,DATFN1(IDX)
TLNE T,ST.PRO
CAME TT,DATCHN(IDX)
JRST CLODI1
.CALL [ SETZ ;If we opened a file, close it
SIXBIT/CLOSE/
SETZ DATCHN(IDX) ]
JFCL
CLODI1: MOVEI T,MFDBUF/2000
PUSHJ P,PAGDAL
MOVEI T,DIRBUF/2000
PUSHJ P,PAGDAL
SETZM DIRLCK
MOVE T,DATSTA(IDX) ;Restore channel status
];END IFN ITS
IFN TNX,[
TLNE T,ST.PRO
TLNN T,ST.NOK
JRST CLODI1
MOVE 1,DATJFN(IDX) ;If we got a JFN, release it
RLJFN
ERJMP .+1
CLODI1:
];TNX
MOVEI TT,(T)
CAIN TT,ST%OPN ;Was the channel open?
HRRI T,ST%CLO ;Yes, then close it
MOVEM T,DATSTA(IDX)
JRST BUFDAL ;Deallocate the core buffer and return
IFN ITS,[
;; Lock the lock for the MFD and UFD pages and associated variables
LCKDIR: SKIPE T,DIRLCK
CAIN IDX,(T)
SKIPA
CERR NER,[Can't have more than one directory open at a time]
HRROM IDX,DIRLCK ;Something random
POPJ P,
;; Map in the MFD
GETMFD: MOVEI T,MFDBUF/2000
PUSHJ P,PAGALO
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW+%CLIMM,,.UII
%CLIMM,,UTILCH
%CLIN,,DATDEV(IDX)
%CLIN,,[SIXBIT /M.F.D./]
%CLIN,,[SIXBIT /(FILE)/]
%CLIN+%CLEND,,DATSNM(IDX)]
POPJ P,
MOVEI T,2000
MOVE TT,[444400,,MFDBUF]
.CALL [ SETZ
SIXBIT /SIOT/
%CLERR,,ERRCOD
%CLIMM,,UTILCH
%CLIN,,TT
%CLIN+%CLEND,,T]
SETZM MFDBUF+MDCHK ;Normally 'M.F.D.
.CLOSE UTILCH,
JFCL
MOVE T,MFDBUF+MDCHK
CAMN T,[SIXBIT /M.F.D./]
AOS (P)
POPJ P,
];ITS
;;; Printing routines
IFN ITS,[
;;; Print directory header info
DIRHED: MOVEI A,[ASCIZ \DONT-REAP NOT-BACKED-UP AUTHOR CREATION-DATE REFERENCE-DATE\]
TLNE D,ST.PRO
JRST DIRSCL ;PROPERTIES command has abbreviated header
PUSHJ P,DIRCLF ;Empty pathname for special information
TLNE D,ST.FST\ST.ALD ;Fast option?
JRST DIRHDE ;Yes, skip rest of heading
MOVEI A,[ASCIZ \SETTABLE-PROPERTIES DONT-REAP NOT-BACKED-UP AUTHOR CREATION-DATE REFERENCE-DATE\]
PUSHJ P,DIRSCL
MOVEI T,2000*36.
MOVEI A,[ASCIZ \BLOCK-SIZE\]
PUSHJ P,DIRDEC
PUSHJ P,DIRFSI
PUSHJ P,DIRCLF
DIRHDE: JRST DIRCLF
;;; Print one file
DIRFIL: SKIPGE DATDRP(IDX) ;Anything left at all to do?
POPJ P, ;No
SKIPE DATNDR(IDX) ;Initialized?
JRST DIRFL1
PUSHJ P,DIRINI ;No, do so
JRST DIRFIL
DIRFL1: PUSHJ P,DIR1FL ;Directory of one file
PUSHJ P,DIRNFL ;Step to next file
POPJ1: AOS (P)
POPJ P,
DIRINI: MOVE TT,DATSNM(IDX) ;Get directory requested
DIRIN1: JUMPE TT,DIRSIM ;Simple case, no directory wildcards
SETZ T,
LSHC T,6
CAIE T,'* ;A wildcard specifier?
JRST DIRIN1
;; The directory has some wildcards, figure out which ones to do
CNT==:1 ;Temporary AC's for sort
LST==:2
DIRWLD: SETO LST, ;LIST _ NIL
SETZ CNT, ;COUNT _ 0
SKIPA D,MFDBUF+MDNAMP
DIRWL1: ADDI D,LMNBLK
CAIL D,2000
JRST DIRWL2 ;End of MFD, go sort
SKIPN TT,MFDBUF(D)
JRST DIRWL1
MOVE B,DATSNM(IDX)
PUSHJ P,DIRMAT ;Star match
JRST DIRWL1 ;No good, try next
MOVEM LST,MFDBUF+1(D)
MOVEI LST,MFDBUF(D) ;LIST _ CONS(D,LIST)
AOJA CNT,DIRWL1
;;; Attempt star matching, pattern in B, test in TT. Clobbers A,T,TT
DIRMAT: CAME B,[SIXBIT /*/] ;Just * matches all
DIRMT1: CAMN B,TT ;The same now?
JRST POPJ1 ;A winner
SETZB A,T
LSHC A,6
LSHC T,6
CAIE A,(T) ;Same character
CAIN A,'* ;Or * in patter
JRST DIRMT1 ;Yes, go on
POPJ P, ;No, a loser
;;; Have all the matching entries linked thru LST, sort them
DIRWST: CAIN CNT,1 ;At end of list?
JRST DRWSTR ;Yes, return it
PUSH P,CNT ;Save count
LSH CNT,-1
PUSHJ P,DIRWST ;Recurse for first section
POP P,CNT
PUSH P,A ;Save value
ADDI CNT,1
LSH CNT,-1
PUSHJ P,DIRWST ;Recurse for second section
POP P,B ;Get first value
MOVEI C,D-1 ;Where to accumulate list
;; Merge two sublists
DIRWSM: JUMPL B,DRWST1 ;No first arg, maybe use second
JUMPL A,DRWSTB ;No second, use first
MOVE T,(A) ;Get second name
MOVE TT,(B) ;Get first name
;; Do magnitude comparison
JUMPL T,DRWSM2 ;T neg?
JUMPL TT,DRWSTA ;No, and TT neg => TT greater
JRST DRWSMC ;Both pos, just compare
DRWSM2: JUMPGE TT,DRWSTB ;T neg and TT pos => T greater
EXCH T,TT ;Both negative, reverse comparison
DRWSMC: CAML T,TT
JRST DRWSTA ;1st greater => take it
DRWSTB: MOVEM B,1(C)
MOVEI C,(B)
MOVE B,1(C)
JRST DIRWSM
DRWSTA: MOVEM A,1(C) ;Enter 1st at head
MOVEI C,(A) ;Transfer it to tail
MOVE A,1(C) ;Get next one
JRST DIRWSM ;And continue
DRWST1: JUMPGE A,DRWSTA ;Use 2nd if any
SETOM 1(C)
MOVE A,D
POPJ P,
DRWSTR: MOVEI A,(LST) ;A _ CAR(LIST)
MOVE LST,1(LST) ;LIST _ CDR(LIST)
SETOM 1(A) ;RPLACD(A,NIL)
POPJ P, ;RETURN(A)
;; Simple case, only one directory
DIRSIM: SETOM DATNDR(IDX) ;Flag that there is no next directory
MOVE T,DATSTA(IDX)
MOVE A,DATSNM(IDX)
TLNE T,ST.ALD
JRST [ MOVEM A,DATFN1(IDX) ;Someplace to store directory name
AOS DATDRP(IDX)
POPJ P,] ;Directories only, skip mapping ufd
;In this special case, we already read in the directory
;when the directory command was processed. So don't call DIRMAP now.
MOVE D,DIRBUF+UDNAMP ;Initialize pointer to first file
TLNN T,ST.PRO
JRST DIRNF1 ;Then advance to next file
MOVEI D,2000-LUNBLK ;Make dummy file block for PROPERTIES command
.CALL [ SETZ
'FILBLK
%CLIN,,DATFN1(IDX)
%CLOUT,,DIRBUF+0(D)
%CLOUT,,DIRBUF+1(D)
%CLOUT,,DIRBUF+2(D)
%CLOUT,,DIRBUF+3(D)
%CLOUT+%CLEND,,DIRBUF+4(D)]
JRST DIRDIE
JRST DIRNF4
DIRWL2: SKIPL A,LST ;If there is anything there,
PUSHJ P,DIRWST ;sort it
MOVEM A,DATNDR(IDX) ;DATNDR _ SORT(LIST)
;; Step to next directory
DIRNDR: SKIPG A,DATNDR(IDX) ;Next directory link
JRST [ SETOM DATDRP(IDX) ;Flag that no files are left to do
POPJ P,] ;Single return for no more
MOVE T,1(A)
MOVEM T,DATNDR(IDX)
MOVE A,(A) ;Sixbit directory name
;; Start going on directory in A
DIRMAP: MOVSI T,ST.ALD
TDNE T,DATSTA(IDX)
JRST [ MOVEM A,DATFN1(IDX) ;Someplace to store directory name
AOS DATDRP(IDX)
POPJ P,] ;Directories only, skip mapping ufd
PUSHJ P,GETUF1
JRST DIRDIE
MOVE D,DIRBUF+UDNAMP ;Initialize pointer to first file
JRST DIRNF1 ;Then advance to next file
;;; Here if we can't get a directory. Give an error over the connection and punt.
DIRDIE: PUSH P,PKTLOC ;Direct data to the async packet
MOVEI T,ASYPKT
MOVEM T,PKTLOC
MOVE A,DATSTA(IDX)
HRRI A,ST%ASY ;Channel now in ASYNC-MARKED state
TLO A,ST.UNC ;Not continuable
MOVEM A,DATSTA(IDX)
TRO F,F.FHN ;Force outputting of a file handle
PUSH P,[DIRDIE+2]
PUSHJ P,OPNERP
PUSHJ P,ICCERP
POP P,PKTLOC
SETOM DATDRP(IDX)
POPJ P,
;;; Map in directory in A
GETUFD: MOVEI T,DIRBUF/2000 ;Allocate space for directory mapping
PUSHJ P,PAGALO
GETUF1: .CALL [ SETZ
SIXBIT /IOPUSH/
%CLIN+%CLEND,,DATCHN(IDX) ]
PUSHJ P,SYSBUG
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW+%CLIMM,,.UII
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,[SIXBIT /.FILE./]
%CLIN,,[SIXBIT /(DIR)/]
%CLIN+%CLEND,,A]
JRST GETUF2
MOVEI T,2000
MOVE TT,[444400,,DIRBUF]
.CALL [ SETZ
SIXBIT /SIOT/
%CLERR,,ERRCOD
%CLIN,,DATCHN(IDX)
%CLIN,,TT
%CLIN+%CLEND,,T]
SETZM DIRBUF+UDNAME
.CALL [ SETZ
SIXBIT /CLOSE/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL
SKIPE DIRBUF+UDNAME
AOS (P)
GETUF2: .CALL [ SETZ
SIXBIT /IOPOP/
%CLIN+%CLEND,,DATCHN(IDX) ]
PUSHJ P,SYSBUG
POPJ P,
;;; Step to next file
DIRNFL: MOVE D,DATDRP(IDX)
MOVSI T,ST.ALD
TDNE T,DATSTA(IDX)
JRST [ JUMPE D,DIRNDR ;If directory already done, move to next
POPJ P,] ;Else continue with it
DIRNF0: ADDI D,LUNBLK
DIRNF1: TLNE D,-1
HLRZS D ;D now points to next file to do
CAIL D,2000 ;Off the end?
JRST DIRNDR ;Yes, step to next directory
MOVE B,DATFN1(IDX) ;Match FN1
MOVE TT,DIRBUF+UNFN1(D)
PUSHJ P,DIRMAT
JRST DIRNF0
MOVS B,DATFN2(IDX) ;Newest or oldest version requested?
CAIE B,(SIXBIT/</)
CAIN B,(SIXBIT/>/)
JRST DIRNF2
MOVE B,DATFN2(IDX) ;Match FN2
MOVE TT,DIRBUF+UNFN2(D)
PUSHJ P,DIRMAT
JRST DIRNF0
DIRNF4: MOVEM D,DATDRP(IDX)
POPJ P,
;;; Next file when only want newest or oldest version of each file.
;;; Matching -only- files with numeric versions seems to be what people want.
;;; We used to include every file with a non-numeric FN2, to be conservative.
;;; DATDRP(IDX) is either the index of the file, or the index
;;; of the next file group in the LH and garbage in the RH.
DIRNF2: MOVE TT,DIRBUF+UNFN2(D)
PUSHJ P,DIRNMP ;Is this a group of versions?
JRST DIRNF0 ;No, just a single file, skip it
MOVE A,DIRBUF+UNFN1(D) ;Yes, find end of the group
MOVEI B,(D)
DIRNF3: ADDI B,LUNBLK
CAIGE B,2000
CAME A,DIRBUF+UNFN1(B)
JRST DIRNF5
MOVE TT,DIRBUF+UNFN2(B)
PUSHJ P,DIRNMP
CAIA
JRST DIRNF3
DIRNF5: HRL D,B ;File to look at next time
MOVS TT,DATFN2(IDX) ;Want oldest of these or newest?
CAIN TT,(SIXBIT/>/)
SKIPA C,[CAMGE TT,A]
MOVE C,[CAMLE TT,A]
MOVE A,DIRBUF+UNFN2(D) ;Get right-adjusted version of first file
TRNN A,77
JUMPN A,[ LSH A,-6
JRST .-1 ]
MOVEI T,(D)
DIRNF6: ADDI T,LUNBLK
CAIL T,(B) ;More versions in group?
JRST DIRNF4 ;No, D points at best one found
MOVE TT,DIRBUF+UNFN2(T) ;Get right-adjusted version of this file
TRNN TT,77
JUMPN TT,[ LSH TT,-6
JRST .-1 ]
XCT C ;Skip if TT is better than A
JRST DIRNF6 ;A,D is still best version
MOVE A,TT ;New best version
HRRI D,(T) ;New file to put in dir listing
JRST DIRNF6
;Skip if sixbit in TT is purely numeric
DIRNMP: MOVEI T,0
LSHC T,6
CAIL T,'0
CAILE T,'9
POPJ P,
JUMPN TT,DIRNMP
JRST POPJ1
;;; Process one file
DIR1FL: MOVE TT,DATSTA(IDX)
TLNE TT,ST.ALD
JRST DIR1AD
MOVE T,DIRBUF+UNRNDM(D)
TLNE T,UNIGFL ;This file deleted?
TLNE TT,ST.DEL\ST.PRO ;Yes, list anyway?
SKIPA A,DATDEV(IDX)
POPJ P, ;No, don't output anything
PUSHJ P,DIRSXO
MOVEI A,[ASCIZ \: \]
PUSHJ P,DIRSTR
MOVE A,DIRBUF+UDNAME
PUSHJ P,DIRSXO
MOVEI A,[ASCIZ \; \]
PUSHJ P,DIRSTR
MOVE D,DATDRP(IDX) ;Get pointer to file
MOVE A,DIRBUF+UNFN1(D)
PUSHJ P,DIRSXO
MOVEI BYTE,40
PUSHJ P,DIRCHO
MOVE A,DIRBUF+UNFN2(D)
PUSHJ P,DIRSXO
PUSHJ P,DIRCLF
MOVSI TT,ST.FST
TDNE TT,DATSTA(IDX) ;Fast option?
JRST DIR1FE ;Yes, skip rest
MOVE T,DIRBUF+UNRNDM(D)
TLNE T,UNLINK ;Is this file a link?
JRST DIR1LN ;Yes, special processing
TLNN T,UNIGFL ;* file?
JRST DIR1F1 ;No, ordinary
MOVEI A,[ASCIZ \DELETED\]
PUSHJ P,DIRSCL
DIR1F1: TLNN T,UNREAP
JRST DIR1F2
MOVEI A,[ASCIZ \DONT-REAP\]
PUSHJ P,DIRSCL
DIR1F2: TLNE T,UNDUMP
JRST DIR1F3
MOVEI A,[ASCIZ \NOT-BACKED-UP\]
PUSHJ P,DIRSCL
DIR1F3: LDB T,[UNPKN DIRBUF+UNRNDM(D)]
MOVEI A,[ASCIZ \PHYSICAL-VOLUME\]
PUSHJ P,DIRDEC
MOVEI T,2000*36.
MOVEI A,[ASCIZ \BLOCK-SIZE\]
PUSHJ P,DIRDEC
PUSHJ P,DIRLN0 ;Length in blocks into T
MOVSI TT,ST.PRO
TDNE TT,DATSTA(IDX)
PUSHJ P,DIR1F5 ;PROPERTIES command, dir may have changed
PUSH P,T ;Save it
MOVEI A,[ASCIZ \LENGTH-IN-BLOCKS\]
PUSHJ P,DIRDEC
POP P,T ;Length in blocks
LDB TT,[UNWRDC DIRBUF+UNRNDM(D)] ;Word count of last block
SKIPE TT
SUBI T,1
LSH T,10.
ADDI T,(TT) ;Word count now in T
PUSH P,T
LDB T,[UNBYTE DIRBUF+UNREF(D)] ;Byte size info
TRZE T,400
JRST [ IDIVI T,100 ;400+100xS+C
JRST DIR1F4]
TRZE T,200
JRST [ IDIVI T,20 ;200+20xS+C
JRST DIR1F4]
SUBI T,36.
JUMPGE T,[IDIVI T,4 ;44+4xS+C
JRST DIR1F4]
MOVMS T ;44-S
SETZ TT, ;C=0
DIR1F4: PUSH P,TT ;Save number of extra bytes
PUSH P,T ;Save byte size
MOVEI A,[ASCIZ \BYTE-SIZE\]
PUSHJ P,DIRDEC
MOVEI T,36.
IDIV T,(P) ;Number of words per byte
IMUL T,-2(P) ;Times number of words
SUB T,-1(P) ;Less number of extra bytes
SUB P,[3,,3]
MOVEI A,[ASCIZ \LENGTH-IN-BYTES\]
PUSHJ P,DIRDEC
DIR1FD: MOVE T,DIRBUF+UNDATE(D)
MOVEI A,[ASCIZ \CREATION-DATE\]
PUSHJ P,DIRDAT
HLLZ T,DIRBUF+UNREF(D)
MOVEI A,[ASCIZ \REFERENCE-DATE\]
PUSHJ P,DIRDAT
LDB T,[UNAUTH DIRBUF+UNREF(D)]
CAIN T,777 ;No author?
JRST DIR1FE
SUB T,MFDBUF+MDNUDS
ASH T,1
SKIPN T,MFDBUF+2000(T) ;Get sixbit directory name
JRST DIR1FE
MOVEI A,[ASCIZ \AUTHOR\]
PUSHJ P,DIRIND
MOVE A,T
PUSHJ P,DIRSXO
PUSHJ P,DIRCLF
DIR1FE: JRST DIRCLF
DIR1F5: .CALL [ SETZ
'FILLEN
%CLIN,,DATFN1(IDX)
%CLOUT,,T ;Length in bytes
%CLOUT+%CLEND,,TT] ;Byte size
JRST DIRDIE
MOVEI A,36.
IDIVM A,TT
IDIV T,TT ;Length in words
ADDI T,1777
LSH T,-10.
POPJ P,
;; Link info output
DIR1LN: MOVEI A,[ASCIZ \LINK-TO\]
PUSHJ P,DIRIND
PUSHJ P,DIRDSC ;Get link descriptor
PUSHJ P,DIRLXO
MOVEI BYTE,";
PUSHJ P,DIRCHO
MOVEI BYTE,40
PUSHJ P,DIRCHO
PUSHJ P,DIRLXO
MOVEI BYTE,40
PUSHJ P,DIRCHO
PUSHJ P,DIRLXO
PUSHJ P,DIRCLF
JRST DIR1FD ;Return to main body
;;; Output link atom b.p. in A
DIRLXO: MOVEI T,6 ;End on six characters
DIRLX0: ILDB BYTE,A
JUMPE BYTE,CPOPJ
CAIN BYTE,'; ; ; ends
POPJ P,
CAIN BYTE,': ; : quotes
ILDB BYTE,A
ADDI BYTE,40
PUSHJ P,DIRCHO
SOJG T,DIRLX0
POPJ P,
;;; Get length in blocks into T
DIRLN0: PUSHJ P,DIRDSC ;Get ufd descriptor
MOVEI T,0
DIRLN1: ILDB B,A
JUMPE B,CPOPJ ;End by 0
CAILE B,UDTKMX ;1-UDTKMX
JRST DIRLN2
ADDI T,(B) ;Take N
JRST DIRLN1
DIRLN2: CAIGE B,UDWPH
AOJA T,DIRLN1 ;Take 1
CAIN B,UDWPH ;Write place holder
JRST DIRLN1
IBP A
IBP A
AOJA T,DIRLN1
;;; Get file descriptor into A. Clobbers B
DIRDSC: LDB A,[UNDSCP DIRBUF+UNRNDM(D)] ;Get link descriptor
IDIVI A,UFDBPW
ADD A,[ 440600,,DIRBUF+UDDESC
360600,,DIRBUF+UDDESC
300600,,DIRBUF+UDDESC
220600,,DIRBUF+UDDESC
140600,,DIRBUF+UDDESC
060600,,DIRBUF+UDDESC](B)
POPJ P,
;;; Directory output, just listing all directories.
;;; DATDRP is the directory name while it is pending, 0 while waiting for the next one.
DIR1AD: MOVE A,DATDEV(IDX)
PUSHJ P,DIRSXO
MOVEI A,[ASCIZ \: \]
PUSHJ P,DIRSTR
MOVE A,DATFN1(IDX)
PUSHJ P,DIRSXO
MOVEI A,[ASCIZ \; \]
PUSHJ P,DIRSTR
PUSHJ P,DIRCLF
PUSHJ P,DIRCLF
SETZM DATDRP(IDX)
POPJ P,
;;; SIXBIT output from A
DIRSXO: MOVE B,A
DIRSO0: JUMPE B,CPOPJ
SETZ A,
LSHC A,6
JUMPE A,DIRSOQ
CAIE A,':
CAIN A,';
JRST DIRSOQ
DIRSO1: MOVEI BYTE,40(A)
PUSHJ P,DIRCHO
JRST DIRSO0
DIRSOQ: MOVEI BYTE,"
PUSHJ P,DIRCHO
JRST DIRSO1
] ;END IFN ITS
IFN TNX,[
DIRHED:
IFN 20X,MOVEI A,[ASCIZ \NOT-BACKED-UP AUTHOR CREATION-DATE REFERENCE-DATE BYTE-SIZE LENGTH-IN-BYTES PROTECTION GENERATION-RETENTION-COUNT ACCOUNT TEMPORARY DELETED DONT-DELETE DONT-REAP\]
IFN 10X,MOVEI A,[ASCIZ \NOT-BACKED-UP AUTHOR CREATION-DATE REFERENCE-DATE BYTE-SIZE LENGTH-IN-BYTES PROTECTION GENERATION-RETENTION-COUNT ACCOUNT TEMPORARY DELETED DONT-DELETE\]
TLNE D,ST.PRO
JRST DIRSCL ;PROPERTIES command has abbreviated header
PUSHJ P,DIRCLF ;Empty pathname for special information
TLNE D,ST.FST\ST.ALD ;Fast option?
JRST DIRHDE ;Yes, skip rest of heading
MOVEI A,[ASCIZ \SETTABLE-PROPERTIES NOT-BACKED-UP AUTHOR CREATION-DATE REFERENCE-DATE BYTE-SIZE LENGTH-IN-BYTES PROTECTION GENERATION-RETENTION-COUNT ACCOUNT TEMPORARY DELETED DONT-DELETE\]
IFN 20X,[
PUSHJ P,DIRSTR
MOVEI A,[ASCIZ \ DONT-REAP\]
];20X
PUSHJ P,DIRSCL
PUSHJ P,DIRFSI
PUSHJ P,DIRCLF
DIRHDE: PUSHJ P,DIRCLF
AOS DATNDR(IDX)
POPJ P,
DIRFIL: SKIPN DATJFN(IDX) ;Still have a file?
POPJ P, ;No, cannot fill in anything
MOVSI TT,ST.ALD
TDNE TT,DATSTA(IDX)
JRST DIRALD
HRROI 1,RESBLK
HRRZ 2,DATJFN(IDX)
MOVE 3,[111110,,JS%PAF]
JFNS
PUSHJ P,DIRRES
PUSHJ P,DIRCLF
MOVSI TT,ST.FST
TDNE TT,DATSTA(IDX) ;Fast option?
JRST DIRFLE ;Yes, skip rest
HRRZ 1,DATJFN(IDX)
IFN 20X,MOVSI 2,.FBLEN
.ELSE, MOVSI 2,.FBUSW+1
MOVEI 3,DIRINF
GTFDB
ERCAL JSYSER
MOVE T,DIRINF+.FBCTL ;Get control bits
MOVSI TT,-NDBITS
DIRFLL: TDNN T,DIRBIT(TT)
JRST DIRFL1
MOVE A,DIRBST(TT)
PUSHJ P,DIRSCL
DIRFL1: AOBJN TT,DIRFLL
HRRZ T,DIRINF+.FBPRT
MOVEI A,[ASCIZ \PROTECTION\]
PUSHJ P,DIROCT
LDB T,[<.BP FB%RET> DIRINF+.FBBYV]
MOVEI A,[ASCIZ \GENERATION-RETENTION-COUNT\]
PUSHJ P,DIRDEC
LDB T,[<.BP FB%BSZ> DIRINF+.FBBYV]
MOVEI A,[ASCIZ \BYTE-SIZE\]
PUSHJ P,DIRDEC
MOVE T,DIRINF+.FBSIZ
MOVEI A,[ASCIZ \LENGTH-IN-BYTES\]
PUSHJ P,DIRDEC
MOVEI T,1000*36.
MOVEI A,[ASCIZ \BLOCK-SIZE\]
PUSHJ P,DIRDEC
LDB T,[<.BP FB%PGC> DIRINF+.FBBYV]
MOVEI A,[ASCIZ \LENGTH-IN-BLOCKS\]
PUSHJ P,DIRDEC
MOVE T,DIRINF+.FBWRT ;Really time of last write
MOVEI A,[ASCIZ \CREATION-DATE\]
PUSHJ P,DIRDAT
MOVEI A,[ASCIZ \REFERENCE-DATE\]
SKIPE T,DIRINF+.FBREF
PUSHJ P,DIRDAT
MOVEI A,[ASCIZ \NOT-BACKED-UP\]
SKIPN DIRINF+.FBBK0
PUSHJ P,DIRSCL
MOVSI T,(AR%NAR)
MOVEI A,[ASCIZ \DONT-REAP\]
TDNE T,DIRINF+.FBBBT
PUSHJ P,DIRSCL
HRRZ 1,DATJFN(IDX)
IFN 20X,[
HRLI 1,.GFLWR ;Really last writer
HRROI 2,RESBLK
GFUST
MOVEI A,[ASCIZ \AUTHOR\]
PUSHJ P,DIRRCL
IRP NAM,,[FBTP1,FBSS1,FBTP2,FBSS2]
MOVEI A,[ASCIZ \NAM\]
SKIPE T,DIRINF+.!NAM
PUSHJ P,DIROCT
TERMIN
]
IFN 10X,[
HRROI 1,RESBLK
HLRZ 2,DIRINF+.FBUSE ;Author
DIRST
JRST .+3
MOVEI A,[ASCIZ \AUTHOR\]
PUSHJ P,DIRRCL
HRROI 1,RESBLK
HRRZ 2,DIRINF+.FBUSE ;Last reader
DIRST
JRST .+3
MOVEI A,[ASCIZ \READER\]
PUSHJ P,DIRRCL
]
HRROI 1,RESBLK
HRRZ 2,DATJFN(IDX)
MOVEI 3,JS%ACT
JFNS
MOVEI A,[ASCIZ \ACCOUNT\]
PUSHJ P,DIRRCL
;; Done with this file, output blank line
DIRFLE: MOVE 1,DATJFN(IDX)
GNJFN
SETZM DATJFN(IDX)
DIRFE1: PUSHJ P,DIRCLF
AOS DATNDR(IDX)
POPJ1: AOS (P) ;Skip return for full file
POPJ P,
DIRALD: SKIPE 2,DATDRN(IDX) ;Have a directory number already?
JRST DIRAL1
PUSHJ P,DIRSTP
POPJ P,
DIRAL1: HRROI 1,RESBLK
DIRST
JRST DIRAL2
IFN 10X,[
MOVEI A,[ASCIZ /DSK:</] ;>
PUSHJ P,DIRSTR
];10X
MOVEI A,RESBLK
PUSHJ P,DIRSTR
IFN 10X,[ ;<
MOVEI BYTE,">
PUSHJ P,DIRCHO
];10X
PUSHJ P,DIRCLF
DIRAL2: PUSHJ P,DIRSTP
SETZM DATDRN(IDX)
JRST DIRFE1
DIRSTP: HRROI 1,RESBLK
MOVE 2,DATJFN(IDX)
IFN 10X,MOVSI 3,(JS%DIR)
.ELSE MOVE 3,[JS%DEV+JS%DIR+JS%PAF]
JFNS
MOVSI 1,(RC%AWL)
HRROI 2,RESBLK
SKIPE 3,DATDRN(IDX)
TLO 1,(RC%STP)
RCDIR
MOVEM 3,DATDRN(IDX)
MOVE 2,3 ;Return in 2
TLNN 1,(RC%NMD\RC%NOM)
JRST POPJ1
PUSHJ P,RELDJF
POPJ P,
DIRBIT: FB%TMP
FB%DEL
IFN 20X,[
FB%DIR
FB%NOD
FB%OFF
IFDEF FB%NDL,FB%NDL ; Twenex release 5 has new name and value
.ELSE [
IFDEF FB%UND,FB%UND
.ELSE FB%PRM
]
];20X
.ELSE 400,,0
NDBITS==:.-DIRBIT
DIRBST: [ASCIZ \TEMPORARY\]
[ASCIZ \DELETED\]
IFN 20X,[
[ASCIZ \DIRECTORY\]
[ASCIZ \DONT-DUMP\]
[ASCIZ \OFFLINE\]
];20X
[ASCIZ \DONT-DELETE\]
;;; Output string in A, then RESBLK, then newline
DIRRCL: PUSHJ P,DIRIND
PUSHJ P,DIRRES
JRST DIRCLF
] ;END IFN TNX
;;; Output indicator
DIRIND: PUSHJ P,DIRSTR
MOVEI BYTE,40
JRST DIRCHO
;;; Output date in T with indicator in A
DIRDAT: PUSHJ P,DIRIND
MOVE A,T
PUSHJ P,DIRDTO
JRST DIRCLF
;;; Output octal number in T for property indicator in A
;;; NOTE: This function knows about returning from its caller
DIROCT: SKIPA B,[8]
DIRDEC: MOVEI B,10.
PUSHJ P,DIRIND
PUSHJ P,DIRNUM
JRST DIRCLF
;;; Just output number in T base in B
DIRNUM: PUSH P,[-1]
JUMPGE T,DIRNM0
MOVEI BYTE,"-
PUSHJ P,DIRCHO
MOVNS T
TLZ T,400000
DIRNM0: IDIVI T,(B)
PUSH P,TT
JUMPN T,DIRNM0
DIRNM1: POP P,BYTE
JUMPL BYTE,CPOPJ
ADDI BYTE,"0
PUSHJ P,DIRCHO
JRST DIRNM1
DIRSCL: PUSHJ P,DIRSTR
DIRCLF: MOVEI A,[.BYTE 7 ? ^M ? ^J]
JRST DIRSTR
IFN TNX,DIRRES: SKIPA A,[440700,,RESBLK]
DIRSTR: HRLI A,440700
DIRST1: ILDB BYTE,A ;Get next character
JUMPE BYTE,CPOPJ ;Terminate on null
PUSHJ P,DIRCHO
JRST DIRST1
DIRCHO: SOJLE BC,REDBF1 ;Unwind when buffer filled
IDPB BYTE,BP
POPJ P,
;;; FILE-SYSTEM-INFO command
;;; The info had better all fit in one packet, or all hell will break loose!
COMFSI: MOVEI A,[ASCIZ \FILE-SYSTEM-INFO \]
PUSHJ P,COMCTL
MOVEI BYTE,215
PUSHJ P,COMCHO
SUBI BC,CHPMXC
MOVNS BC ;So DIRCHO will act like COMCHO
IFN 20X,MOVEI IDX,MAXIDX
PUSHJ P,DIRFSI
SUBI BC,CHPMXC
MOVNS BC
PUSHJ P,COMSND
JRST CTLLOP
DIRFSI:
IFN 10X,[
MOVEI A,[ASCIZ\DISK-SPACE-DESCRIPTION \]
PUSHJ P,DIRSTR
HRLOI 1,.DVDES+.DVDSK ;DSK: DESIGNATOR
GDSKC ;1 gets pages used, 2 gets pages left
ADD 1,2
MOVEI B,10.
MOVE T,2
PUSHJ P,DIRNUM
MOVEI A,[ASCIZ\ disk pages free out of \]
PUSHJ P,DIRSTR
MOVE T,1
PUSHJ P,DIRNUM
MOVEI A,[ASCIZ\ (\]
PUSHJ P,DIRSTR
MOVE T,1
SUB T,2
IMULI T,100.
IDIV T,1
PUSHJ P,DIRNUM
MOVEI A,[ASCIZ\% full)\]
JRST DIRSTR
];10X
IFN 20X,[
MOVEI A,[ASCIZ\DISK-SPACE-DESCRIPTION \]
PUSHJ P,DIRSTR
HRRZ 2,DATJFN(IDX)
JUMPE 2,FRESTR ;Not really anything here, no JFN.
MOVSI 1,(RC%EMO)
RCDIR
TLNE 1,(RC%NOM)
JRST FRESTR ;No match, presumably wildcard was used.
MOVE 1,3
GTDAL ;Get directory allocation.
MOVEI B,10.
MOVE T,2 ;Permanent quota
PUSHJ P,DIRNUM
MOVEI A,[ASCIZ / used, /]
PUSHJ P,DIRSTR
CAML 3,[377777,,0]
JRST [MOVEI A,[ASCIZ /+INF/]
PUSHJ P,DIRSTR
JRST .+3]
MOVE T,3
PUSHJ P,DIRNUM
MOVEI A,[ASCIZ / allowed. /]
PUSHJ P,DIRSTR
FRESTR: MOVE 1,[SIXBIT /DEVNAM/]
SYSGT
HRRZ D,2 ;Table#
MOVEI C,1 ;Should be 1st device name.
GSTRNM: HRLZ 1,C
HRR 1,D ;Offset,,table#
GETAB
JFCL
;;This won't work if # of structures = STRN!
;; HLRZ 2,1 ;If no more devices, it's SIXBIT/STRnnn/
;; CAIN 2,(SIXBIT /STR/)
;; JRST [ MOVEI A,[ASCIZ/ disk pages free./]
;; JRST DIRSTR ]
MOVE 3,[440700,,STRNAM]
ST6TO7: SETZ 2, ;Turn sixbit structure name into asciz
ROTC 1,6 ;string.
ADDI 2,40
IDPB 2,3
JUMPN 1,ST6TO7
SETZ 2,
IDPB 2,3 ;Null terminate.
;;Start of UTexas change
HRROI 1,STRNAM ;Set up to get device designator
STDEV
ERJMP ENDSTR
MOVE 1,2 ;Set up device designator
MOVEM 1,DEVDEG ;Save device designator for later
DVCHR ;Check device type
ERJMP ENDSTR
LDB 3,[221100,,2] ;Get DV%TYP
CAIE 3,.DVDSK ;Is it a disk?
JRST ENDSTR ;No
;;End of UTexas change
MOVEI BYTE,40
PUSHJ P,DIRCHO
PUSHJ P,DIRCHO
MOVEI A,STRNAM
PUSHJ P,DIRSTR
MOVEI BYTE,": ;<sp><sp>STRUCTURE:<sp>nnnnn
PUSHJ P,DIRCHO
MOVEI BYTE,40
PUSHJ P,DIRCHO
MOVE 1,DEVDEG ;[UTexas] Restore device designator
GDSKC
MOVE T,2 ;Free
MOVEI B,10.
PUSHJ P,DIRNUM
GNSTRN: AOJA C,GSTRNM ;Step to next structure.
ENDSTR: MOVEI A,[ASCIZ/ disk pages free./]
JRST DIRSTR
];20X
IFN ITS,[
MOVEI A,[ASCIZ \PHYSICAL-VOLUME-FREE-BLOCKS\]
PUSHJ P,DIRSTR
MOVE T,[SQUOZE 0,NQS]
.EVAL T,
.LOSE %LSSYS
MOVSI C,-1
TLC C,-1(T) ;AOBJN pointer
MOVE T,[SQUOZE 0,QSFT]
.EVAL T,
.LOSE %LSSYS
PUSH P,T
MOVE T,[SQUOZE 0,QPKID]
.EVAL T,
.LOSE %LSSYS
PUSH P,T
MOVEI B,10.
DIRFR0: MOVE TT,(P) ;QPKID
ADDI TT,(C) ;(Q)
MOVSS TT
HRRI TT,T
.GETLOC TT,
JUMPL T,DIRFR1
MOVEI BYTE,",
TRNN C,-1
MOVEI BYTE,40
PUSHJ P,DIRCHO
PUSHJ P,DIRNUM
MOVEI BYTE,":
PUSHJ P,DIRCHO
MOVE TT,-1(P) ;QSFT
ADDI TT,(C) ;(Q)
MOVSS TT
HRRI TT,T
.GETLOC TT,
PUSHJ P,DIRNUM
DIRFR1: AOBJN C,DIRFR0
SUB P,[2,,2]
POPJ P,
];ITS
;;; Filename completion command
COMCPL: SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
SETZ D, ;Clear options here
CPLOPT: TRNE F,F.NWL ;End of options?
JRST CPLFNM
PUSHJ P,COMRD5 ;Get token
JUMPL BC,COMBAD
CPLOLP: MOVEI T,CPLLEN-1
CPLOL1: CAME A,CPLTAB(T)
SOJGE T,CPLOL1
JUMPL T,[CERR UUO,[Unknown COMPLETE option]]
XCT CPLACT(T)
JRST COMBAD
JRST CPLOPT
CPLTAB: ASCII \DELET\
ASCII \READ\
ASCII \WRITE\
ASCII \OLD\
ASCII \NEW-O\
CPLLEN==.-CPLTAB
CPLACT: TLOA D,ST.DEL
TLZA D,ST.OUT
TLOA D,ST.OUT
TLZA D,ST.NOK
TLOA D,ST.NOK
IFN TNX,[
;;; Local storage
DEFDEV==RESBLK
DEFDIR==DEFDEV+1
DEFNAM==DEFDIR+1
DEFTYP==DEFNAM+1
DEFSTR==DEFTYP+1
;Parse only GTJFN doesn't quite work on Tenex
;So, if we get no such device or no such directory, flush that all together and
;hope the system defaults help.
IFN 10X,[
CPLFIX: MOVEI BYTE,215
DPB BYTE,BP ;Put back old end of line
MOVE BP,3 ;Get old byte pointer
MOVE BC,4
CPLFX1: SOJL BC,CPLFX2
ILDB BYTE,BP
JUMPN BYTE,CPLFX3
CPLFX2: PUSHJ P,JSYSER ;End and no special character
CPLFX3: CAIN BYTE,^V
JRST [ IBP BP
SOJA BC,CPLFX1]
CAIE BYTE,(1) ;One we want
JRST CPLFX1
]
CPLFNM:
IFN 10X,MOVE 3,BP ;Save current byte pointer
.ALSO MOVE 4,BC
TLO D,ST.PON
PUSHJ P,COMGJF ;Get JFN for default
IFE 10X, PUSHJ P,JSYSER
.ELSE [ JRST [ CAIN 1,GJFX16 ;No such device
JRST [ MOVEI 1,":
JRST CPLFIX]
CAIN 1,GJFX17 ;No such directory <
JRST [ MOVEI 1,">
JRST CPLFIX]
IRPS STR,,[DEV DIR NAME TYP]
SETZM DEF!STR ;Forget the damned defaults
TERMIN
JRST CPLFN1]
];10X
MOVE 2,1 ;Setup for JFNS
MOVEI 1,DEFSTR ;Some string space
SETZ A,
MOVSI 3,100000 ;Device initially...
IRPS STR,,[DEV DIR NAM TYP]
MOVEI 1,1(1) ;Make sure pointing to fresh word...
HRLI 1,440700
MOVEM 1,DEF!STR ;Save pointer to this section.
JFNS
IDPB A,1
LSH 3,-3 ;Shift down file-part field...
TERMIN
HRROI 1,1(1)
PUSH P,1
MOVSI 3,000010 ;Generation field...
JFNS
POP P,1
HRLI 1,440700
ILDB 1,1
CAIN 1,"*
TLO D,ST.DIR ;Remember if should have wild default
MOVE 1,2
RLJFN ;Done with this JFN
JFCL
CPLFN1: SETZM GTJBLK
MOVE A,[GTJBLK,,GTJBLK+1]
BLT A,GTJBLK+.GJBFP ;Clear out long call GTJFN block
MOVEM BP,DEFSTR ;Save user's string
PUSHJ P,COMEUS ;Find end of it
JRST [TRZN F,F.NWL ;Must be terminated with a newline
JRST COMBAD
JRST .+2]
JRST .-2 ;Terminated by space, so keep searching
MOVEI 1,33 ;Put in escape to get completion
DPB 1,BP
SETZ 1,
IDPB 1,BP
;;; Now have defaults and user's string. If this is an input file, the idea is to
;;; keep trying GTJFN without allowing new files and various default conditions
;;; until we manage to win.
TLNN D,ST.OUT
SKIPA C,[-NCPLMT,,CPLMTH] ;Completion method routines
HRROI C,CPLOUT ;Completion for output
TLNN D,ST.NOK ;New file ok?
ADD C,[1,,0] ;No, skip last method
;;; Here to try next method
CPLLUP:.GJTYP==.GJEXT ;Nothing is consistent
IRPS STR,,[DEV DIR NAM TYP]
MOVE 1,DEF!STR
MOVEM 1,GTJBLK+.GJ!STR
TERMIN
MOVE 1,[.NULIO,,.NULIO]
MOVEM 1,GTJBLK+.GJSRC
MOVEI 1,2 ;Two extra words
MOVEM 1,GTJBLK+.GJF2
HRROI 1,JFNSTR
MOVEM 1,GTJBLK+.GJCPP
MOVEI 1,30.*5
MOVEM 1,GTJBLK+.GJCPC
MOVSI 1,(GJ%OLD\GJ%FLG\GJ%XTN)
TLNE D,ST.DEL
TLO 1,(GJ%DEL)
TLNE D,ST.DIR
IOR 1,[GJ%IFG+.GJALL]
XCT (C)
MOVEM 1,GTJBLK+.GJGEN
MOVEI 1,GTJBLK
MOVE 2,DEFSTR
GTJFN
JRST CPLNXT ;Failed, try next method
MOVE 3,[111110,,JS%PAF] ;Device, directory, filename, file type, version
;;; Now, if the user didn't really type the generation number, don't give it back
SKIPL GTJBLK+.GJGEN ;GJ%FOU supplied?
JRST [ TLNE 1,(GJ%UHV) ;No, highest existing = 0
JRST .+2
JRST .+3]
TLNE 1,(GJ%NHV) ;Yes, next higher = 0
TLZ 3,(JS%GEN)
MOVE 2,1 ;Jfn
HRROI 1,JFNSTR
JFNS
MOVE 1,2
RLJFN
JFCL
MOVEI A,[ASCIZ \OLD\]
MOVSI 1,(GJ%OLD)
TDNN 1,GTJBLK+.GJGEN
MOVEI A,[ASCIZ \NEW\]
JRST CPLDON
CPLNXT: AOBJN C,CPLLUP ;Keep trying and finally return typescript as is
LDB 1,GTJBLK+.GJCPP
SETZ 2,
CAIN 1,33 ;Clear altmode from user's typescript
DPB 2,GTJBLK+.GJCPP
MOVEI A,[ASCIZ \NIL\]
CPLDON: PUSH P,A
MOVEI A,[ASCIZ \COMPLETE \]
PUSHJ P,COMCTL
POP P,A
PUSHJ P,COMSTO
MOVEI BYTE,215
PUSHJ P,COMCHO
MOVEI A,JFNSTR
PUSHJ P,COMSTO
MOVEI BYTE,215
PUSHJ P,COMCHO
PUSHJ P,COMSND
JRST CTLLOP
CPLMTH: JFCL
SETZM GTJBLK+.GJEXT
SETZM GTJBLK+.GJNAM
PUSHJ P,CPLNBT
TLZ 1,(GJ%OLD)
NCPLMT==.-CPLMTH
CPLOUT: TLC 1,(GJ%FOU\GJ%OLD\GJ%NEW)
CPLNBT: SETZM GTJBLK+.GJNAM
SETZM GTJBLK+.GJEXT
POPJ P,
];END OF COMPLETION COMMAND FOR TNX
IFN ITS,[
;;; ITS COMPLETION COMMAND
CPLFNM: MOVEI IDX,MAXIDX ;Use probe variables for filename parsing etc.
HLLM D,DATSTA(IDX) ;Save status bits
SETZM DATSNM(IDX)
SETZM DATFN2(IDX)
PUSHJ P,COMPFN ;Parse the filename spec for the default
IRPS SYL,,[SNM FN1 FN2]
MOVE TT,DAT!SYL(IDX) ;Save the defaults
MOVEM TT,DEF!SYL'
TERMIN
SETZM DATSNM(IDX)
SETZM DATFN2(IDX)
PUSHJ P,COMPFN ;Parse the user's string
PUSHJ P,LCKDIR ;Get DIRLCK
;; First, find the directory
SKIPN A,DATSNM(IDX) ;Start from any specified directory
MOVE A,DEFSNM ;None, start from default
SKIPN A
MOVE A,HSNAME ;If no default, use default default: user's homedir
PUSHJ P,GETUFD ;Read in the directory
CAIA
JRST CPLFN3
;; Directory doesn't exist, try completion on it
PUSHJ P,GETMFD ;Read in the MFD
JRST CPLFN9 ;Can't do much without any dirs
PUSHJ P,CMPLT0
SKIPA D,MFDBUF+MDNAMP
CPLFN1: ADDI D,LMNBLK
CAIL D,2000
JRST CPLFN2
MOVE A,MFDBUF(D)
PUSHJ P,CMPLT1
JRST CPLFN1
CPLFN2: MOVE A,CMPLTW ;Result of directory completion
MOVEM A,DATSNM(IDX) ;Return it whether or not directory exists
PUSHJ P,GETUFD
JRST CPLFN9 ;Directory doesn't exist, stop now
CPLFN3: MOVEM A,DATSNM(IDX)
;; Now scan the directory. First we plug in the defaults and complete.
;; If that yields an existent file, or this is for output, take that as
;; the result. Otherwise complete without plugging in the defaults.
;; If that yields an existent file, take it. Otherwise take the results
;; of plugging in the defaults and completing if new-file is okay.
;; We don't distinguish defaulting FN1 and defaulting FN2.
SKIPN A,DATFN1(IDX)
MOVE A,DEFFN1
SKIPN B,DATFN2(IDX)
JRST [ MOVE B,DEFFN2 ;Note, never take ">" from the defaults
CAMN B,[SIXBIT/>/]
SETZ B,
JRST .+1 ]
PUSHJ P,CPLDIR
JRST [ MOVSI T,ST.OUT ;No existent file, doing output?
TDNN T,DATSTA(IDX)
JRST CPLFN4 ;No, try without defaults
JRST CPLFN7 ] ;Matches non-existent file
JRST CPLFN7 ;Matches possibly-existent file
CPLFN4: PUSH P,A ;Save results of completion with default
PUSH P,B
MOVE A,DATFN1(IDX) ;Try again without defaults
MOVE B,DATFN2(IDX)
PUSHJ P,CPLDIR
JRST [ MOVSI T,ST.NOK ;That didn't work either, new file okay?
TDNN T,DATSTA(IDX)
JRST CPLFN9 ;No, no completions found
POP P,B ;Yes, take the completion-with-defaults
POP P,A
JRST .+2 ]
SUB P,[2,,2]
; A and B now have the result of the completion. Determine NEW/OLD status.
CPLFN7: MOVEM A,DATFN1(IDX)
MOVEM B,DATFN2(IDX)
SKIPA D,DIRBUF+UDNAMP ;See if completed file really exists
CPLF7A: ADDI D,LUNBLK
CAIL D,2000
JRST CPLF7B
CAME A,DIRBUF+UNFN1(D)
JRST CPLF7A
CAMN B,DIRBUF+UNFN2(D)
JRST CPLF7C
JUMPE B,CPLF7C ;The file exists
CAME B,[SIXBIT/>/]
CAMN B,[SIXBIT/</]
JRST CPLF7C
JRST CPLF7A
CPLF7B: SKIPA A,[[ASCIZ/NEW/]]
CPLF7C: MOVEI A,[ASCIZ/OLD/]
JRST CPLDON
;Failure return
CPLFN9: MOVEI A,[ASCIZ/NIL/]
CPLDON: PUSH P,A
MOVEI T,MFDBUF/2000
PUSHJ P,PAGDAL
MOVEI T,DIRBUF/2000
PUSHJ P,PAGDAL
SETZM DIRLCK
MOVEI A,[ASCIZ \COMPLETE \]
PUSHJ P,COMCTL
POP P,A
PUSHJ P,COMSTO
MOVEI BYTE,215
PUSHJ P,COMCHO
PUSHJ P,COMRF1 ;Read back completed file name (sans host)
MOVEI BYTE,215
PUSHJ P,COMCHO
PUSHJ P,COMSND
JRST CTLLOP
;Complete A and B against the directory in DIRBUF, return results in A and B
;Skip-return if any completions found
;Note that cannot complete FO BA to FOO BAR if FORD 1 also exists, i.e.
;it completes the two filenames separately. Hopefully this is all right,
;although the Lisp machine completing reader is smarter.
;No attempt to do binary search although system has sorted the dir.
CPLDIR: PUSHJ P,CMPLT0 ;Start completing FN1
SKIPA D,DIRBUF+UDNAMP
CPLDR1: ADDI D,LUNBLK
CAIL D,2000
JRST CPLDR2
MOVE A,DIRBUF+UNFN1(D)
PUSHJ P,CMPLT1
JRST CPLDR1
CPLDR2: MOVE C,CMPLTW ;Completed FN1
SKIPGE CMPLTF ;Any completions found?
JRST CPLDR5 ;Nope
CAME B,[SIXBIT/>/] ;FN2 of < or > always matches
CAMN B,[SIXBIT/</]
JRST CPLDR5
MOVE A,B ;Start completing FN2 against files with that FN1
PUSHJ P,CMPLT0
SKIPA D,DIRBUF+UDNAMP
CPLDR3: ADDI D,LUNBLK
CAIL D,2000
JRST CPLDR4
MOVE A,DIRBUF+UNFN2(D)
CAMN C,DIRBUF+UNFN1(D)
PUSHJ P,CMPLT1
JRST CPLDR3
CPLDR4: JUMPN B,CPLDR6 ;When completing a blank FN2, special hair
SKIPE CMPLTF ;Exactly one match?
JRST CPLDR5 ;No, result remains blank (i.e. ">")
MOVE B,CMPLTW ;Yes, is it all numeric?
CPLDR7: MOVEI A,0 ;If so, we won't count it since it's a version not a type
LSHC A,6
CAIL A,'0
CAILE A,'9
JRST CPLDR6 ;Blank FN2 matches a single filetype
JUMPN B,CPLDR7
TDZA B,B ;Result remains blank
CPLDR6: MOVE B,CMPLTW ;Completed FN2
CPLDR5: MOVE A,C ;Completed FN1
SKIPL CMPLTF ;Any completions found?
AOS (P) ;Yes, take skip return
POPJ P,
CMPLTA==CLODAT ;Trying to keep the impure down to one page
CMPLTM==CLOLEN
;;; Completion of sixbit words
;;; Set up to complete the word in A
;;; After calling this, call CMPLT1 any number of times then pick
;;; up your result out of CMPLTW, which is either the original argument
;;; (in which case CMPLTF is negative), or else is the shortest existent
;;; extension of that.
CMPLT0: MOVEM A,CMPLTA ;Word to match
SETO T,
TDNE A,T
JRST [ LSH T,-6
JRST .-1 ]
SETCAM T,CMPLTM ;Mask for fixed characters
SETOM CMPLTF' ;No completions found yet
MOVEM A,CMPLTW' ;Word found so far (result of completion)
SETCAM T,CMPLTX' ;Mask for valid characters in that
POPJ P,
;;; Use the sixbit in A as a possible completion.
CMPLT1: MOVE TT,A
XOR TT,CMPLTA
TDNE TT,CMPLTM ;Does it match the fixed characters?
POPJ P, ;No.
AOSE CMPLTF ;First completion found?
JRST CMPLT2 ;No
MOVEM A,CMPLTW ;Yes, save as result
SETO T, ;and compute its length
TDNE A,T
JRST [ LSH T,-6
JRST .-1 ]
SETCAM T,CMPLTX
POPJ P,
CMPLT2: MOVE TT,A ;Two completions, take their common prefix
XOR TT,CMPLTW
MOVE T,CMPLTX
TDNE TT,T
JRST [ LSH T,6
JRST .-1 ]
MOVEM T,CMPLTX
ANDM T,CMPLTW
POPJ P,
];ITS
;;; Property changing command
COMCNG: SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
TRZN F,F.NWL ;Should be newline
JRST COMBAD
TRNN F,F.FHN ;Use an open file?
JRST CNGFIL ;Nope, need a filename
PUSHJ P,CNGLOP
PUSHJ P,FILERR ;Failed
JRST CNGDN1
CNGFIL: MOVEI IDX,MAXIDX ;Use dummy IDX
IFN ITS,[
PUSHJ P,COMPFN
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBIT,,.UAI
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,DATFN1(IDX)
%CLIN,,DATFN2(IDX)
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR
]
IFN TNX,[
MOVSI D,ST.DEL
PUSHJ P,COMGJF
PUSHJ P,JSYSER
MOVEM 1,DATJFN(IDX) ;Save jfn
]
PUSHJ P,CNGLOP
CAIA
JRST CNGDON
IFN ITS,[
.CALL [ SETZ
SIXBIT /CLOSE/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL
];ITS
IFN TNX,PUSHJ P,RELDJ1 ;Failed, release file
PUSHJ P,FILERR
;;; Done changing things, close the file, etc.
CNGDON:
IFN ITS,[
.CALL [ SETZ
SIXBIT /CLOSE/
%CLIN+%CLEND,,DATCHN(IDX)]
JFCL
];ITS
IFN TNX,PUSHJ P,RELDJ1
CNGDN1: MOVEI A,[ASCIZ \CHANGE-PROPERTIES\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
JRST CTLLOP
CNGLOP: JUMPLE BC,POPJ1 ;Done when end or just blank line
TRZ F,F.NWL
PUSHJ P,COMR10 ;Get property name
JRST COMBAD
CNGOLP: MOVEI C,CNGLEN
CNGOL1: SOJL C,[CERR UKP,[Unknown property]]
CAMN A,CNGTAB-1(C)
CAME B,CNGTAB(C)
SOJA C,CNGOL1
HRRZ T,CNGACT(C) ;Get routine
PUSHJ P,(T)
IFN 20X,[
SKIPL CNGACT(C) ;If sign (flag) bit on, then we want
JRST CNGLOP ;to do something else besides this
HRRZ T,CNGALT(C) ;operation, so look in the parallel
PUSHJ P,(T) ;table for de poop.
];20X
JRST CNGLOP
;;; NOTE: If you change this, be sure to update the list of settable properties at
;;; the start of DIRHED.
CNGTAB:
IFN 20X+ITS, ASCII \DONT-REAP\ ;DONT-REAP
ASCII \NOT-BACKED\ ;NOT-BACKED-UP
ASCII \AUTHOR\ ;AUTHOR
ASCII \CREATION-D\ ;CREATION-DATE
ASCII \REFERENCE-\ ;REFERENCE-DATE
IFN TNX,[
ASCII \BYTE-SIZE\ ;BYTE-SIZE
ASCII \LENGTH-IN-\ ;LENGTH-IN-BYTES
ASCII \PROTECTION\ ;PROTECTION
ASCII \GENERATION\ ;GENERATION-RETENTION-COUNT
ASCII \ACCOUNT\ ;ACCOUNT
ASCII \TEMPORARY\ ;TEMPORARY
ASCII \DELETED\ ;DELETED
ASCII \DONT-DELET\ ;DONT-DELETE
]
CNGLEN==.-CNGTAB
IFN ITS,[
CNGACT: SIXBIT /SREAPB/ ? -1,,CNGBIT ;DONT-REAP
SIXBIT /SDMPBT/ ? 0,,CNGBIT ;NOT-BACKED-UP
SIXBIT /SAUTH/ ? CNGAUT ;AUTHOR
SIXBIT /SFDATE/ ? CNGDAT ;CREATION-DATE
SIXBIT /SRDATE/ ? CNGDAT ;REFERENCE-DATE
CNGBIT: HLRE A,CNGACT(C)
PUSH P,A ;Get sense of boolean
PUSHJ P,COMRD5
JFCL
CAMN A,[ASCII /NIL/]
SETCMM (P)
POP P,A
;; Perfor system call for this routine, argument in A
CNGCAL: MOVE B,CNGACT-1(C)
.CALL [ SETZ
SIXBIT /CALL/
%CLERR,,ERRCOD
%CLIN,,B
%CLIN,,DATCHN(IDX)
%CLIN+%CLEND,,A]
JRST CNGERR
POPJ P,
CNGAUT: PUSHJ P,COMSXI ;Read sixbit author name
JRST CNGCAL
CNGDAT: PUSHJ P,COMDTI ;Read a date
JRST CNGCAL
] ;END IFN ITS
IFN TNX,[
CNGACT:
IFN 20X,-1 ? .ARNAR,,CNGABT ;DONT-REAP
-1 ? .FBBK0,,CNGBIT ;NOT-BACKED-UP
SFUST ? 400000\.SFLWR,,CNGSTR ;AUTHOR (Sign bit means dualistic)
-1 ? 400000\.FBWRT,,CNGDAT ;CREATION-DATE
-1 ? .FBREF,,CNGDAT ;REFERENCE-DATE
FB%BSZ ? .FBBYV,,CNGDEC ;BYTE-SIZE
-1 ? .FBSIZ,,CNGDEC ;LENGTH-IN-BYTES
IFN 20X,[77,,-1] .ELSE [0,,-1] ? .FBPRT,,CNGOCT ;PROTECTION
FB%RET ? .FBBYV,,CNGDEC ;GENERATION-RETENTION-COUNT
SACTF ? CNGSTR ;ACCOUNT
FB%TMP ? .FBCTL,,CNGBIT ;TEMPORARY
FB%DEL ? .FBCTL,,CNGBIT ;DELETED
IFDEF FB%NDL,FB%NDL ; Twenex release 5 has new name and value
.ELSE [
IFDEF FB%UND,FB%UND
.ELSE FB%PRM
]
.FBCTL,,CNGBIT ;DONT-DELETE
IFN 20X,[
CNGALT: 0 ? 0
0 ? 0
SFUST ? .SFAUT,,CNGST1 ;real 20X AUTHOR
-1 ? .FBCRV,,CNGDA1 ;real 20x CREATION-DATE
;there had better not be any more sign bits!
];20X
CNGBIT: PUSHJ P,COMRD5
CAMN A,[ASCII \NIL\]
TDZA A,A
SETO A,
CNGFDB: HRRZ 1,DATJFN(IDX)
HLL 1,CNGACT(C)
TLZ 1,400000 ;Remove that flag bit.
MOVE 2,CNGACT-1(C) ;Mask
MOVE 3,A ;New value
IFN 20X,PUSHJ P,TRYCON
CHFDB
ERJMP CNGERR
POPJ P,
IFN 20X,[
CNGABT: PUSHJ P,COMRD5 ;Modify archival information via ARCF
CAMN A,[ASCII \NIL\]
SKIPA 3,[.ARCLR]
MOVEI 3,.ARSET
HRRZ 1,DATJFN(IDX)
HLRZ 2,CNGACT(C)
ARCF
ERJMP CNGERR
POPJ P,
];20X
CNGDAT: PUSHJ P,COMDTI
JRST CNGFDB
IFN 20X,[
CNGDA1: HRRZ 1,DATJFN(IDX)
HLL 1,CNGALT(C)
MOVE 2,CNGALT-1(C) ;Mask
MOVE 3,A ;Old value (had better still be there)
PUSHJ P,TRYCON
CHFDB
ERJMP .+1 ;OK if we fail.
POPJ P,
];20X
CNGDEC: PUSHJ P,COMDCI
JRST CNGRFD
CNGOCT: PUSHJ P,COMOCI
;;Here if right justified
CNGRFD: MOVE T,CNGACT-1(C) ;Mask
JFFO T,.+1
SETCM T,CNGACT-1(C)
LSH T,(TT)
MOVNS TT
LSH T,(TT)
JFFO T,.+2
JRST CNGFDB ;No shifting necessary
MOVEI T,36.
SUBI T,(TT)
LSH A,(T)
JRST CNGFDB
CNGSTR: MOVE 2,BP
MOVEM 2,SAVEBP
PUSHJ P,COMEUS ;Find end
SKIPA
JRST .-2 ;Terminated by space, so keep searching
SETZ 1,
DPB 1,BP ;Insure terminating NULL
HRRZ 1,DATJFN(IDX)
HLL 1,CNGACT(C)
TLZ 1,400000 ;Make sure that flag bit is off...
XCT CNGACT-1(C)
ERJMP CNGERR
POPJ P,
IFN 20X,[
CNGST1: HRRZ 1,DATJFN(IDX)
HLL 1,CNGALT(C)
MOVE 2,SAVEBP
XCT CNGALT-1(C)
ERJMP .+1 ;OK if we fail...
POPJ P,
];20X
];END IFN TNX
;;; Error, take error return from CNGLOP
CNGERR: SUB P,[1,,1] ;Flush return to CNGLOP
POPJ P,
;;; Expunge directory command
COMEXP: SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
SETZ D, ;Clear options here
MOVEI IDX,MAXIDX ;Use the temporary channel for this
EXPOPT: TRNE F,F.NWL ;End of options?
JRST EXPFNM
PUSHJ P,COMRD5 ;Get token
JUMPL BC,COMBAD
IFN ITS,CERR UUO,[Unknown EXPUNGE option]
IFN TNX,[
EXPOLP: MOVEI T,EXPLEN-1
EXPOL1: CAME A,EXPTAB(T)
SOJGE T,EXPOL1
JUMPL T,[CERR UUO,[Unknown EXPUNGE option]]
XCT EXPACT(T)
JRST COMBAD
JRST EXPOPT
EXPTAB: ASCII \TEMPO\ ;TEMPORARY
EXPLEN==.-EXPTAB
EXPACT: SKIPA
EXPFNM: TLO D,ST.ALD ;Allow wildcards
PUSHJ P,PRSDIR ;Return JFN in 1, directory number in 3
PUSHJ P,JSYSER
RLJFN ;Don't need that JFN anymore.
JFCL
PUSH P,[0] ;Initial sum of freed pages.
EXPFN0: MOVEM 3,WILDIR
MOVE 1,3 ;Directory#
GTDAL
ERCAL JSYSER
PUSH P,2 ;Returns allocated pages in AC2
IFN 10X,[
HRRZ 1,WILDIR ;Directory number
DELDF ;Expunge (never skips, and blows it on ERCAL)
];10X
IFN 20X,[
SETZ 1,
MOVE 2,WILDIR
DELDF ;Expunge.
ERCAL JSYSER
];20X
MOVE 1,WILDIR
GTDAL ;Get new allocation
ERCAL JSYSER
POP P,1 ;Old allocation
SUB 1,2 ;1/ pages freed
ADDM 1,(P) ;Accumulate.
IFN 20X,[
MOVSI 1,(RC%STP\RC%AWL) ;Step to next directory
HRROI 2,RESBLK ;Pointer to directory string
MOVE 3,WILDIR ;Old dir#
RCDIR
ERCAL JSYSER
TLNN 1,(RC%NMD\RC%NOM) ;No More Directories?
JRST EXPFN0 ; Yes more, so go do next.
];20X
];TNX
IFN ITS,[ ;Always returns success
EXPFNM: PUSHJ P,COMPFN ;PARSE THE FILENAME
PUSH P,[0] ;No space is ever reclaimed
];ITS
MOVEI A,[ASCIZ \EXPUNGE \]
PUSHJ P,COMCTL
POP P,A
PUSHJ P,COMDCO
MOVEI BYTE,215 ;<freed pages>NL<directory expunged>NL
PUSHJ P,COMCHO
IFN TNX,PUSHJ P,COMRES
IFN ITS,[
MOVE A,DATSNM(IDX)
PUSHJ P,COMSXO
MOVEI BYTE,";
PUSHJ P,COMCHO
];ITS
MOVEI BYTE,215
PUSHJ P,COMCHO
PUSHJ P,COMSND
JRST CTLLOP
IFN TNX,[
;Return JFN in 1, directory number in 3 (skip on success)
;Allows wildcard directories on Tops-20 if ST.ALD is set
;Failure takes non-skip return with error code in 1, or blows out
PRSDIR: TLO D,ST.PON ;Parse only: don't care if there are no files in dir
PUSHJ P,COMGDJ ;Get JFN
POPJ P,
PUSH P,1 ;Save JFN
HRROI 1,RESBLK
MOVE 2,(P)
IFN 10X,MOVSI 3,(JS%DIR) ;Tenex wants directory with no delimiters
.ELSE MOVE 3,[110000,,JS%PAF] ;Just want device and directory
JFNS
ERCAL SYSBUG
HRRZS (P) ;Kill flags in LH(JFN)
IFN 20X,[
MOVSI 1,(RC%AWL) ;Recognize directory, allowing wildcards
TLNN D,ST.ALD
MOVSI 1,(RC%EMO)
];20X
IFN 10X,MOVSI 1,(RC%EMO) ;Tenex's RC%AWL is too slow, even when no wildcards present
HRROI 2,RESBLK
RCDIR ;Get dir# (initial if wildcard)
ERJMP PRSDI2 ;Syntax error
TLNE 1,(RC%NOM)
JRST PRSDI1
POP P,1
JRST POPJ1
PRSDI1: MOVEI 1,.FHSLF ;Fake error return from RCDIR
MOVEI 2,GJFX17
SETER
PRSDI2: MOVEI 1,.FHSLF ;Get last error
PUSHJ P,$GETER
MOVEI 2,GJFX17 ;If no error code, use No Such Directory
POP P,1 ;Release the parse-only JFN
RLJFN
JFCL
HRRZ 1,2 ;Return just error number
POPJ P,
];TNX
IFN TNX,[
;;; Enable your capabilities.
COMENA: SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
SETZ D, ;Mask of priv bits.
COMEN1: JUMPLE BC,DOENA ;Jump if no options left
PUSHJ P,COMRD5
JFCL
MOVEI T,ENALEN-1 ;Number of ENABLE options
COMEN2: CAME A,ENATAB(T) ;Match?
SOJGE T,COMEN2 ; No, keep checking.
JUMPL T,[CERR UUO,[Unknown ENABLE/DISABLE option]]
XCT ENAACT(T)
JRST COMEN1
ENATAB: ASCII /ALL/
ASCII /OPERA/
ASCII /WHEEL/
ENALEN==.-ENATAB
ENAACT: SETO D,
TRO D,SC%OPR
TRO D,SC%WHL
DOENA: MOVEI 1,.FHSLF
RPCAP ;Get your capabilities.
IOR 3,D ;Turn on requested bits.
EPCAP
MOVEI A,[ASCIZ /ENABLE-CAPABILITIES/]
DOEN1: PUSHJ P,COMCTL
MOVEI 1,.FHSLF
RPCAP ;Possible in 2, enabled in 3.
MOVSI T,-NPRIVS ;Return state of your priviledges.
DOEN2: HRRZ TT,PRVTAB(T)
TRNN 2,(TT)
JRST DOEN3 ; You don't have this priv.
MOVEI BYTE,40
PUSHJ P,COMCHO
HLRZ A,PRVTAB(T)
PUSHJ P,COMSTO ;You do, so send the name and then T if
MOVEI BYTE,40 ;it's on, else NIL.
PUSHJ P,COMCHO
MOVEI A,[ASCIZ /NIL/] ;This priv is disabled...
TRNE 3,(TT)
MOVEI A,[ASCIZ /T/] ;(and this is is enabled)
PUSHJ P,COMSTO
DOEN3: AOBJN T,DOEN2
MOVEI BYTE,215
PUSHJ P,COMCHO
PUSHJ P,COMSND
JRST CTLLOP
PRVTAB: [ASCIZ /WHEEL/],,SC%WHL ;Privs whose status we
[ASCIZ /OPERATOR/],,SC%OPR ;will return
[ASCIZ /CONFIDENTIAL-INFORMATION-ACCESS/],,SC%CNF
[ASCIZ /MAINTENANCE/],,SC%MNT
[ASCIZ /IPCF/],,SC%IPC
[ASCIZ /ENQ-DEQ/],,SC%ENQ
[ASCIZ /ARPANET-WIZARD/],,SC%NWZ
[ASCIZ /ABSOLUTE-ARPANET-SOCKETS/],,SC%NAS
NPRIVS==.-PRVTAB
COMDIS: SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
MOVEI 1,.FHSLF
RPCAP
MOVE D,3 ;What you have on now.
COMDI1: JUMPLE BC,DODIS ;Jump if no options left
PUSHJ P,COMRD5
JFCL
MOVEI T,ENALEN-1
COMDI2: CAME A,ENATAB(T)
SOJGE T,COMDI2 ; No, keep checking.
JUMPL T,[CERR UUO,[Unknown ENABLE/DISABLE option]]
XCT DISACT(T)
JRST COMDI1
DISACT: TRZ D,SC%WHL+SC%OPR
TRZ D,SC%WHL
TRZ D,SC%OPR
DODIS: MOVEI 1,.FHSLF
RPCAP
MOVE 3,D
EPCAP
MOVEI A,[ASCIZ /DISABLE-CAPABILITIES/]
JRST DOEN1
];TNX (ENABLE AND DISABLE COMMANDS)
;;; Connect/access directory commands
IFN 20X,[
COMCWD: PUSH P,[[ASCIZ/CWD/]]
PUSH P,[AC%CON] ;Just want to connect
JRST .+3
COMACD: PUSH P,[[ASCIZ/ACCESS/]]
PUSH P,[AC%OWN] ;Want ownership access to a directory
];20X
IFN 10X,COMCWD:
IFN TNX,[
SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
JUMPLE BC,CWDIRF ;No good
MOVE 2,BP ;Save byte ref copy
PUSHJ P,COMEUS ;Eat till end of line, hopefully
JUMPL BC,CWDIRF ;Should be a password following
SETZ T, ;Tie it off
DPB T,BP
MOVE 3,2 ;Get start of fellow
ILDB 3,3 ;See if null
JUMPE 3,[GJINF ;Sure enough, get user number into 1
MOVE 2,1 ;Do an RCDIR on that
JRST .+1]
MOVSI 1,(RC%EMO) ;See if it exists
RCDIR
ERCAL JSYSER
TLNE 1,(RC%NOM) ;Did it?
CERR DNF,[No such directory]
MOVEM 3,RESBLK+.ACDIR ;Save directory number
MOVEM BP,RESBLK+.ACPSW ; and password start
MOVE 3,BP ;See if password is null
ILDB 3,3
SKIPN 3
SETZM RESBLK+.ACPSW ;Don't include a pointer if null password
SETOM RESBLK+.ACJOB ;-1 means current job
PUSHJ P,COMEUS ;Scan until end of password
SETZ T, ; and tie it off as usual
DPB T,BP
IFN 20X,[
POP P,1 ;Get back connect/access code
HRRI 1,3 ;3 elements
MOVEI 2,RESBLK ; here
ACCES
];20X
IFN 10X,[
HRRZ 1,RESBLK+.ACDIR ;Directory number and no options
MOVE 2,RESBLK+.ACPSW ;String pointer to password
CNDIR
];10X
ERCAL JSYSER ;Give an error return here
IFN 20X,POP P,A ;Name of command for success reply
IFN 10X,MOVEI A,[ASCIZ \CWD\]
PUSHJ P,COMCTL
MOVEI BYTE,215 ;ACCESS<NL>directory name
PUSHJ P,COMCHO
HRROI 1,RESBLK ;Build full directory specification
MOVE 2,RESBLK+.ACDIR ;Get directory number
DIRST
JFCL ;Ignore errors
PUSHJ P,COMRES ;Send the directory spec
PUSHJ P,COMSND
JRST CTLLOP ;All done
CWDIRF: CERR BUG,[Illegal request format (no directory name)]
];END IFN TNX
;;; Create directory
COMCRD: SKIPN USERID
IFN OZ, PUSHJ P,AUTLOG
.ELSE CERR NLI,[Not logged in]
IFN TNX,[
IFN 10X,[
MOVE T,[-777,,1] ;MUST FIND A FREE DIRECTORY SLOT
CRDFND: HRROI 1,JFNSTR
HRRZ 2,T
DIRST
SKIPA
AOBJN T,CRDFND
JUMPGE T,[CERR CCD,[No free directory slots]]
HRRZM T,CRDBLK+.CDNUM
MOVSI 2,(CD%NUM)
];IFN 10X
.ELSE SETZ 2, ;DEFAULT OPTIONS
SETZM CRDBLK+.CDMOD ;JUST IN CASE
CRDOPT: TRNE F,F.NWL ;NEW LINE TERMINATED OPEN COMMAND?
JRST CRDNAM
PUSHJ P,COMRD5 ;GET NEXT TOKEN
JUMPL BC,COMBAD
CRDOLP: MOVEI T,CRDLEN-1 ;LENGTH OF OPTION TABLE
CRDOL1: CAME A,CRDTAB(T) ;MATCH?
SOJGE T,CRDOL1 ;NOPE, KEEP ON
JUMPL T,[CERR UUO,[Unknown CREATE-DIRECTORY option]]
ASH T,1
MOVE TT,CRDACT(T) ;GET BIT TO SET
IOR 2,TT
XCT CRDACT+1(T) ;CALL PARSER
JRST COMBAD ;PARSING ERROR
MOVEM A,CRDBLK(TT) ;STICK INTO PARAMETER BLOCK
JRST CRDOPT
CRDTAB: ASCII \PASSW\
ASCII \WORKI\
ASCII \CAPAB\
ASCII \FILES\
ASCII \REPEA\
ASCII \PERMA\
ASCII \FILE-\
ASCII \PROTE\
ASCII \GENER\
ASCII \USER-\
ASCII \DIREC\
ASCII \SUBDI\
ASCII \ACCOU\
CRDLEN==.-CRDOPT
CRDACT: CD%PSW+.CDPSW ? PUSHJ P,CRDPSW
CD%LIQ+.CDLIQ ? PUSHJ P,CRDLIQ
CD%PRV+.CDPRV ? PUSHJ P,CRDPRV
CD%MOD+.CDMOD ? PUSHJ P,CRDDIR
CD%MOD+.CDMOD ? PUSHJ P,CRDRLM
CD%LOQ+.CDLOQ ? PUSHJ P,CRDLOQ
CD%FPT+.CDFPT ? PUSHJ P,CRDFPT
CD%DPT+.CDDPT ? PUSHJ P,CRDDPT
CD%RET+.CDRET ? PUSHJ P,CRDRET
CD%UGP+.CDUGP ? PUSHJ P,CRDUGP
CD%DGP+.CDDGP ? PUSHJ P,CRDDGP
CD%SDQ+.CDSDQ ? PUSHJ P,CRDSDQ
CD%DAC+.CDDAC ? PUSHJ P,CRDDAC
CRDPSW:
CRDDAC: MOVE A,BP
PUSHJ P,COMEUS
JFCL
SETZ B,
DPB B,BP
JRST POPJ1
CRDLIQ: CRDLOQ: CRDRET:
CRDSDQ: PUSHJ P,COMDCI
JRST POPJ1
CRDPRV: PUSHJ P,COMOCI
JRST POPJ1
CRDDIR: MOVE A,CRDBLK+.CDMOD
TLO A,(CD%DIR)
JRST POPJ1
CRDRLM: MOVE A,CRDBLK+.CDMOD
TLO A,(CD%RLM)
JRST POPJ1
CRDFPT:
CRDDPT: PUSHJ P,COMOCI
HLL A,500000
JRST POPJ1
IFN 10X,[
CRDUGP:
CRDDGP: SETZ B,
CRDGRP: PUSHJ P,COMDCI
MOVEI C,1
LSH 1,(A)
IORI B,C
TRNN F,F.NWL
JRST CRDGRP
JRST POPJ1
];10X
.ELSE [
CRDUGP: SKIPA A,[JFNSTR]
CRDDGP: MOVEI A,JFNSTR+11.
PUSH P,A
MOVE B,A
HRLI B,-10.
CRDGRP: AOBJP B,[CERR BUG,[Too many directory groups]]
PUSHJ P,COMDCI
MOVEM A,(B)
TRNN F,F.NWL
JRST CRDGRP
POP P,A
SUBI B,-1(A)
HRRM B,(A)
JRST POPJ1
];NOT 10X
CRDNAM:
IFN 20X,[
MOVE 1,BP
PUSHJ P,COMEUS
];20X
.ELSE [
CRDNM1: SOJL BC,COMBAD
ILDB BYTE,BP
CAIE BYTE,"<
JRST CRDNM1
MOVE 1,BP
CRDNM2: SOJL BC,COMBAD
ILDB BYTE,BP
CAIE BYTE,">
JRST CRDNM2
];NOT 20X
SETZ T,
DPB T,BP
HRRI 2,CRDBLK
SETZ 3, ;NO PASSWORD
CRDIR
ERCAL JSYSER
];IFN TNX
IFN ITS,[
TRNN F,F.NWL ;MUST END IN NEWLINE
JRST COMBAD
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW+%CLIMM,,.UAI
%CLIMM,,UTILCH
%CLIN,,[SIXBIT /DSK/]
%CLIN,,[SIXBIT /.FILE./]
%CLIN,,[SIXBIT /(DIR)/]
%CLIN+%CLEND,,USERID]
JRST [ MOVEI A,%ENSDR
JRST CRDNM4 ]
.CLOSE UTILCH,
MOVEI IDX,MAXIDX ;Use the temporary channel for this
PUSHJ P,COMPFN ;PARSE THE FILENAME
.CALL [ SETZ
SIXBIT /OPEN/
%CLERR,,ERRCOD
%CLBTW+%CLIMM,,.UII
%CLIN,,DATCHN(IDX)
%CLIN,,DATDEV(IDX)
%CLIN,,[SIXBIT /..NEW./]
%CLIN,,[SIXBIT /(UDIR)/]
%CLIN+%CLEND,,DATSNM(IDX)]
SKIPA A,ERRCOD
MOVEI A,%ENSFL ;NO ERROR IF DIR ALREADY EXISTS
CAIE A,%ENSFL
CRDNM4: PUSHJ P,FILERR ;WRONG ERROR => CANNOT CREATE DIR
];IFN ITS
MOVEI A,[ASCIZ \CREATE-DIRECTORY\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
JRST CTLLOP ;All done
IFN ITS,[
COMCRL: TRZN F,F.NWL ;Newline?
JRST COMBAD ;Nope, bad command format
MOVEI IDX,MAXIDX ;Use the temporary channel for this
PUSHJ P,COMPFN ;Parse the filename for the link
TRZN F,F.NWL ;Check for correct format
JRST COMBAD
PUSH P,DATDEV(IDX) ;Save link name
PUSH P,DATFN1(IDX)
PUSH P,DATFN2(IDX)
PUSH P,DATSNM(IDX)
MOVE T,BC ;Compensate for incompetently-defined protocol
IDIVI T,4 ;by appending NL to end of command
ADD T,BP
IBP T
SOJGE TT,.-1
MOVEI TT,215
DPB TT,T
AOS BC
PUSHJ P,COMPFN ;Parse the name to link to
TRZN F,F.NWL ;Check for correct format
JRST COMBAD
JUMPG BC,COMBAD
.CALL [ SETZ
SIXBIT /MLINK/
%CLERR,,ERRCOD ;Error code
%CLIN,,-3(P)
%CLIN,,-2(P)
%CLIN,,-1(P)
%CLIN,,0(P)
%CLIN,,DATFN1(IDX)
%CLIN,,DATFN2(IDX)
%CLIN+%CLEND,,DATSNM(IDX)]
PUSHJ P,FILERR ;File error, tell about it
SUB P,[4,,4]
MOVEI A,[ASCIZ \CREATE-LINK\]
PUSHJ P,COMCTL
PUSHJ P,COMSND
JRST CTLLOP
] ;END IFN ITS
;;; Core buffer allocator
BUFALO: MOVEI T,BUFBAS(IDX) ;Index
SETZM DATBPT(IDX) ;Pointer is zero, meaning virgin buffer
SETZM DATBCT(IDX) ;No room left in buffer
SETZM DATLWD(IDX) ;No last word
IFN ITS,PUSHJ P,PAGALO
LSH T,10. ;Make into address
IFN TNX,[
SETMM (T) ;Access page to create it
SETMM 1000(T) ;Both half-pages
] ;END IFN TNX
MOVEM T,DATBUF(IDX) ;Remember base of buffer
POPJ P,
IFN ITS,[
PAGALO: .CALL [ SETZ
SIXBIT /CORBLK/
%CLIMM,,%CBNDW+%CBNDR ;Write and read access
%CLIMM,,%JSELF ;Into own job
%CLIN,,T ;c(T) is page number
%CLIMM+%CLEND,,%JSNEW] ;Fresh page
CERR NER,[System virtual memory full]
POPJ P,
] ;END IFN ITS
;;; Core buffer deallocator
BUFDAL: MOVEI T,BUFBAS(IDX)
SETZM DATBPT(IDX)
SETZM DATBCT(IDX)
SETZM DATLWD(IDX) ;No last word
SETZM DATBUF(IDX)
IFN ITS,PUSHJ P,PAGDAL
IFN TNX,[
MOVNI 1,1 ;-1 means unmapping a page
MOVE 2,T ;Page number in right half
ADD 2,T ;in half-pages
HRLI 2,.FHSLF ;Process handle in left half
IFN 20X,[
MOVE 3,[SETZ 2] ;Remove 2 half-pages
PMAP
ERCAL CTLERR
];20X
IFN 10X,[
SETZ 3, ;Delete page
PMAP
ERCAL CTLERR
AOS T ;Other half page
PMAP
ERCAL CTLERR
];10X
] ;END IFN TNX
POPJ P,
IFN ITS,[
PAGDAL: .CALL [ SETZ
SIXBIT /CORBLK/
%CLIMM,,0 ;Delete page
%CLIMM,,%JSELF
%CLIN+%CLEND,,T]
.LOSE %LSSYS
POPJ P,
] ;END IFN ITS
;;; IOC error and asynchronous mark transmitters
;;; Both of these routines get called with all interrupts deffered and therefore can use a
;;; shared packet
;;; A contains DATSTA(IDX)
;;; This must be called so that a POPJ returns to "top level".
;;; c(D)+1 contains error code,,pointer to asciz string
;;; c(D)+2 has return address
ASYERR: PUSH P,PKTLOC ;Direct data to the async packet
MOVEI T,ASYPKT
MOVEM T,PKTLOC
HRRI A,ST%ASY ;Channel now in ASYNC-MARKED state
TLO A,ST.UNC ;But uncontinuable
MOVEM A,DATSTA(IDX)
TRO F,F.FHN ;Force outputting of a file handle
MOVEI A,[ASCIZ \ERROR \]
PUSHJ P,COMCTL ;This will output a transaction ID, which will be ignored
HLLZ A,1(D) ;Get error code
PUSHJ P,COMSXO
MOVEI BYTE,40
PUSHJ P,COMCHO
HRRZ A,1(D) ;Now output the error string
PUSHJ P,COMSTO
MOVEI T,CO%ASY
DPB T,[$CPKOP+ASYPKT]
DPB BC,[$CPKNB+ASYPKT]
IFN ITS,[
MOVEI T,CTRLO ;Perhaps have to send this over the control connection
TRNN IDX,1 ;Except if we are already sending data, use IDX's channel
MOVE T,CHACHN(IDX)
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIN,,T
%CLIMM+%CLEND,,ASYPKT]
.LOSE %LSSYS
TRNN IDX,1 ;if more packets might come in, defer interrupts
JRST ASYRET
MOVE T,CHABIT(IDX) ;Defer interrupts on this channel until continued
IORM T,SSYDF2 ;Update saved copy of DF2
.SUSET [.SIDF2,,T]
] ;END IFN ITS
IFN TNX,[
MOVE 1,CTLJFN
TRNN IDX,1
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOPKS
MOVEI 3,ASYPKT
MTOPR
ERCAL CTLERR
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
DIC
] ;END IFN TNX
ASYRET: POP P,PKTLOC
MOVE A,DATSTA(IDX) ;Insure A stays set up correctly
JRST @2(D)
;;; c(D)+1 contains continuation address
ICCERR: PUSH P,PKTLOC ;Direct data to the async packet
MOVEI T,ASYPKT
MOVEM T,PKTLOC
HRRI A,ST%ASY ;Channel now in ASYNC-MARKED state
TLZ A,ST.UNC ;They are continuable
MOVEM A,DATSTA(IDX)
HRRZ T,1(D) ;Get continuation address
MOVEM T,DATICN(IDX) ;Remember in case user end asks us to go on
TRO F,F.FHN ;Force outputting of a file handle
MOVEI A,[ASCIZ \ERROR \]
PUSHJ P,COMCTL ;Start off error packet, open failed error code
IFN ITS,[
.CALL [ SETZ
'STATUS
%CLIN,,DATCHN(IDX)
%CLOUT+%CLEND,,C ]
.LOSE %LSSYS
HLRZ D,C ;Get just the IOC error
ANDI D,37000
PUSHJ P,ERR3 ;Get the 3-letter code
HLRZ D,C ;Put error code in standard place
];END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
PUSHJ P,$GETER ;Get last error that happened
PUSHJ P,CTLERR
HRRZM 2,D ;The number of the error
PUSHJ P,ERR3 ;Get the 3-letter code
];TNX
MOVSS A
PUSHJ P,COMSXO
MOVEI A,[ASCIZ \ R \] ;Recoverable error (probably)
PUSHJ P,COMSTO
PUSHJ P,ERRMSG ;Output the error message now
PUSHJ P,ICCERP ;Send packet
POP P,PKTLOC
SUB P,[1,,1] ;Flush the old return address
POPJ P, ;And return to "superior" of routine that had error
;;; Send IOC error packet
ICCERP: MOVEI T,CO%ASY
DPB T,[$CPKOP+ASYPKT]
DPB BC,[$CPKNB+ASYPKT]
IFN ITS,[
MOVEI T,CTRLO ;Perhaps have to send this over the control connection
TRNN IDX,1 ;Except if we are already sending data, use IDX's channel
MOVE T,CHACHN(IDX)
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIN,,T
%CLIMM+%CLEND,,ASYPKT]
.LOSE %LSSYS
TRNN IDX,1 ;If more packets might come in, defer interrupts
JRST ICCRET
MOVE T,CHABIT(IDX) ;Defer interrupts on this channel until continued
IORM T,SSYDF2 ;Update saved copy of DF2
; Runs at interrupt level -- the interrupt top-level
; will setup the saved defer word before dismissing.
] ;END IFN ITS
IFN TNX,[
MOVE 1,CTLJFN
TRNN IDX,1
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOPKS
MOVEI 3,ASYPKT
MTOPR
ERCAL CTLERR
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
DIC
] ;END IFN TNX
ICCRET: MOVE A,DATSTA(IDX) ;Insure A stays set up correctly
POPJ P,
;;; Recieved a new packet. Write it to the appropriate file. IDX set up, but packet
;;; not read from system. Since we can only get one interrupt at a time, we can use a
;;; common packet buffer for the data until/unless we get an IOC error in which case
;;; the data must be saved in the allocated buffer.
WRIONE:
IFN ITS,[
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIN,,CHACHN(IDX)
%CLIMM+%CLEND,,WRIPKT]
.LOSE %LSSYS ;HMM...THIS BETTER NOT HAPPEN
] ;END IFN ITS
IFN TNX,[
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOPKR
MOVEI 3,WRIPKT
MTOPR
ERCAL CTLERR
] ;END IFN TNX
SKIPL A,DATSTA(IDX) ;CHANNEL ACTIVE?
JRST WRIBAD ;HMMM...CHANNEL NOT ACTIVE, IGNORE THE PACKET
LDB T,[WRIPKT+$CPKOP] ;GET THE OPCODE
CAIN T,CO%SYN ;Synchronous mark, process it (ignoring channel state)
JRST WRIOSY
JRST @WRIDSP(A) ;ACTIONS TO FOLLOW DEPEND UPON CHANNEL STATE
;Dispatch table
WRIDSP: WRICLO ;CHANNEL CLOSED
WRIOPN ;CHANNEL OPEN, NORMAL PROCESSING
WRIASY ;ASYNCHRONOUS MARKED
WRISYN ;SYNCHRONOUS MARKED STATE
WRIEOF ;EOF STATE
;Channel closed, at eof, or sync or asynch mark. Interrupts shouldn't happen
; Channel cannot stay in synchronous mark state for any amount of time, so this shouldn't
; happen either
;These are all reasons a data packet can get thrown away
WRICLO: AERR WRILUZ,BUG,[Data packet being discarded because channel closed]
WRIASY: AERR WRILUZ,BUG,[Data packet being discarded because channel async-marked]
WRISYN: AERR WRILUZ,BUG,[Data packet being discarded because channel sync-marked]
WRIEOF: AERR WRILUZ,BUG,[Data packet being discarded because channel at eof]
WRIBAD: AERR WRILUZ,BUG,[Data packet being discarded because channel not active]
WRILUZ: TLNN A,ST.SYN ;Expecting sync mark?
AOS (P) ;Nope, don't take any more interrupts
POPJ P, ;Return and perform appropriate action
;Channel in open state, only one allowed to receive a new packet
WRIOPN: CAIN T,CO%BDT ;BINARY DATA
JRST WRIBIN
CAIN T,CO%TXT ;TEXT DATA
JRST WRITXT
CAIN T,CO%EOF ;END OF FILE?
JRST WRIOEO
AERR WRILUZ,BUG,[Illegal packet opcode]
;Synchronous mark received
WRIOSY: TLZE A,ST.SYN ;WAS ONE EXPECTED
JRST WRISY0 ;YES, THROW IT AWAY AND PREPARE FOR MORE DATA
HRRI A,ST%SYN ;ELSE PUT CHANNEL INTO SYNC MARKED STATE
MOVEM A,DATSTA(IDX)
IFN ITS,[
MOVE T,CHABIT(IDX) ;Defer interrupts on this channel until mark processed
IORM T,SSYDF2 ;Update saved DF2
.SUSET [.SIDF2,,T]
] ;END IFN ITS
IFN TNX,[
MOVEI 1,.FHSLF
MOVE 2,CHABIT(IDX)
DIC
] ;END IFN TNX
AOS (P)
POPJ P, ;RETURN AND DISMISS INTERRUPT
WRISY0: TLZ A,ST.SYN ;Make sure sync mark is no longer expected
PUSHJ P,@DATSYA(IDX) ;Call routine to handle receipt of sync mark
MOVEM A,DATSTA(IDX) ;Routine may have altered status
POPJ P,
;EOF received
WRIOEO: PUSHJ P,WRIFOR ;FORCE OUT ANY REMAINING BUFFERS
HRRI A,ST%EOF ;PUT CHANNEL IN EOF STATE
MOVEM A,DATSTA(IDX)
POPJ P, ;RETURN AND DISMISS INTERRUPT
;Text data received
;Note: ITS SIOT is much faster if you always send a multiple of 5 characters
;so that everything stays on word boundaries. So we will move any residual
;part word down to the front of the buffer and save it for next time, setting
;DATBCT to the number of characters saved and DATBPT to point after them.
WRITXT: TLNE A,ST.BIN ;FILE OPEN IN BINARY MODE?
WRIIDO: AERR WRILUZ,BUG,[Illegal data opcode]
SETZ BC,
MOVE BP,DATBUF(IDX) ;USE BUFFER TO HOLD BYTES
HRLI BP,440700 ;7 BIT BYTES
SKIPE DATBPT(IDX)
MOVE BP,DATBPT(IDX) ;POINT AFTER OLD STUFF IN BUFFER
LDB T,[WRIPKT+$CPKNB] ;NUMBER OF BYTES
ADDM T,DATRCV(IDX)
MOVE TT,[441000,,WRIPKT+%CPKDT]
;;; Note: Assumption is that even if the packet consisted of all newlines the buffer could
;;; not be overflowed. If this is not the case, then something else has to be hacked
;;; here.
WRITX1: SOJL T,WRITX0 ;DONE WHEN NO MORE BYTES
ILDB BYTE,TT ;ELSE GET NEXT BYTE
TLNN A,ST.RAW ;If raw mode, don't translate
XCT CHR210(BYTE) ;Convert to PDP-10 code
SKIPA ;Non-skip means character not processed
JRST WRITX1 ;Skip means character has been processed
IDPB BYTE,BP
AOJA BC,WRITX1
WRITX0: JUMPE BC,CPOPJ ;If no bytes to write out (0 length packet), return and dismis
ADDM BC,DATLEN(IDX) ;Keep track of number of bytes written
MOVE BP,DATBUF(IDX) ;Write starting from beginning of buffer
HRLI BP,440700
ADD BC,DATBCT(IDX) ;Include characters left over from last time
MOVE T,BC ;Round down to multiple of a word
IDIVI T,5
IMULI T,5
SUB BC,T ;Number of characters that will be left over
MOVEM BC,DATIOC(IDX)
IFN ITS,[
.CALL [ SETZ
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,BP
%CLIN+%CLEND,,T]
JFCL ;Here if IOC error
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,BP
MOVN 3,T
JUMPE 3,.+3
SOUT
ERJMP .+1
MOVN T,3
MOVE BP,2
] ;END IFN TNX
MOVEM T,DATBCT(IDX) ;Save the byte count remaining within the word-aligned part
MOVEM BP,DATBPT(IDX) ;and the byte pointer to not-yet-output chars
JUMPE T,WRITX2 ;If everything SIOT'ed, go handle residue
IOCERR WRITX2 ;Else IOC error, continuation when fixed up after SIOT done
WRITX2: SKIPN BC,DATIOC(IDX) ;Get number characters to be saved for next time
JRST [ SETZM DATBPT(IDX) ? POPJ P, ] ;No characters
CAIL BC,5
PUSHJ P,CTLERR ;This can't happen
MOVEM BC,DATBCT(IDX)
MOVE T,DATBPT(IDX)
;; Don't need to make BP agree with ITS on TOPS-20, since this IBP equalizes them
IBP T ;Points to first byte to be saved for next time
MOVE TT,(T) ;Move that word down to the front
MOVE BP,DATBUF(IDX) ;Make a byte pointer to after them
HRLI BP,440700
IBP BP
SOJG BC,.-1
MOVEM BP,DATBPT(IDX)
MOVEM TT,(BP)
POPJ P,
;Binary data received
WRIBIN: TLNN A,ST.BIN ;MUST BE A BINARY MODE FILE
JRST WRIIDO
SKIPE T,DATBPT(IDX) ;ARE WE IN THE MIDDLE OF A PREVIOUS OPERATION?
JRST WRIBI0 ;YES, SO CONTINUE PROCESSING IT
HRRZ T,DATBYT(IDX)
CAIE T,16. ;16 BIT BYTE MODE?
JRST WRIBI1 ;NOPE, SO NEED SPECIAL HANDLING ANYWAY
LDB T,[WRIPKT+$CPKNB] ;NUMBER OF BYTES
MOVEI D,(T) ;COPY INTO D
LSH T,-1 ;Number of bytes getting written
ADDM T,DATLEN(IDX)
LSH T,-1 ;NUMBER OF PDP-10 WORDS, ROUNDED DOWN
MOVE TT,[444400,,WRIPKT+%CPKDT]
IFN ITS,[
.CALL [ SETZ ;WRITE THE DATA DIRECTLY FROM THE PACKET
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,TT ;POINTER
%CLIN+%CLEND,,T]
SKIPA ;IOC error
JUMPE T,WRIBI2 ;WROTE OUT ALL THE DATA, PROCEED
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,TT ;Pointer
MOVN 3,T ;Negative count -- output this many bytes
JUMPE 3,.+3
SOUT
ERJMP .+2
JRST [PUSHJ P,ITSBP
MOVE TT,2 ;Get updated pointer
JRST WRIBI2]
MOVN T,3
MOVE TT,2
] ;END IFN TNX
MOVE B,DATBUF(IDX) ;SAVE PACKET IN IDX BUFFER
MOVEI C,(B) ;COPY FOR TERMINATION CONDITION
HRLI B,WRIPKT
BLT B,%CPMXW-1(C) ;SAVE ALL OF PACKET
SUBI C,WRIPKT ;OFFSET FOR BYTE POINTER
ADD TT,C
MOVEM TT,DATBPT(IDX) ;SAVE POINTER
MOVEM T,DATBCT(IDX) ;AND SAVE COUNT
IOCERR WRIBI5 ;GIVE THE IOC ERROR, CONTINUATION
WRIBI5: MOVE TT,DATBPT(IDX) ;IOC ERROR RECOVERY PUTS FINAL BP HERE
SETZM DATBPT(IDX) ;No longer need pointer
MOVE D,DATBUF(IDX) ;SAVED PACKET, AND NEED TO GET BYTE COUNT BACK
LDB D,[$CPKNB (D)]
WRIBI2: TRNN D,3 ;DID WE GET AN ODD NUMBER OF BYTES?
POPJ P, ;NOPE, THEN DONE WITH PACKET
;Here if 16 bit byte mode, but have an odd number of bytes. Next packet will have to do
; it slowly
LSH D,-2 ;NUMBER OF WORDS - 1
IBP TT ;POINT AT NEXT BYTE TO BE DONE
MOVE T,(TT) ;GET THE BYTE
MOVE TT,DATBUF(IDX) ;ADDRESS IN WHICH TO SAVE
MOVEM T,(TT) ;SAVE THE WORD CONTAINING THE BYTE IN THE BUFFER
HRLI TT,242000 ;A POINTER TO IT
MOVEM TT,DATBPT(IDX)
MOVEI T,1 ;ONE BYTE REMAINS
MOVEM T,DATBCT(IDX)
POPJ P, ;THEN WE ARE DONE
;Here if non-16bit byte mode but no bytes left over from last time, byte size in T
WRIBI1: SETZM DATBCT(IDX) ;Make sure byte count is 0
HRLI T,440000 ;Prototype byte pointer
DPB T,[300600,,T] ;Deposit correct byte size into pointer
HRR T,DATBUF(IDX) ;Pointer to buffer
;;; Fall into WRIBI0
;Here if had some bytes left over from last time, T has the pointer to last byte written
WRIBI0: LDB BC,[WRIPKT+$CPKNB] ;COUNT OF BYTES IN PACKET
LSH BC,-1 ;16 bit mode only has half as many
ADDM BC,DATLEN(IDX) ;Keep track of number of more bytes to write
MOVEI C,(BC) ;Save number of bytes
ADD C,DATBCT(IDX) ;Add in number of bytes left over
HRRZ TT,DATBUF(IDX) ;Pointer for SIOT (used later)
HRLI TT,444400
JUMPE BC,WRIBI6 ;If no bytes in packet, finish up here and now
HRRI B,(T) ;THIS IS THE FIRST WORD TO SIOT OUT OF
MOVE BP,[442000,,WRIPKT+%CPKDT]
WRIBI4: SOJL BC,WRIBI3 ;LOOP OVER ALL BYTES
ILDB BYTE,BP
IDPB BYTE,T
JRST WRIBI4
WRIBI3: HRRZ D,DATBPW(IDX)
CAIGE C,(D) ;Enough bytes to make up a word?
JRST WRIBI6 ;Nope
MOVE D,T ;Must increment byte pointer in case last byte was written
IBP D
SUBI D,(B)
HRRZI B,(D) ;Get rid of byte pointer part
IFN ITS,[
.CALL [ SETZ
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,TT
%CLIN+%CLEND,,B]
SKIPA ;IOC error
JUMPE B,WRIBI6 ;Done writing successfully, so go on
MOVEM TT,DATBPT(IDX)
MOVEM B,DATBCT(IDX)
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,TT
MOVN 3,B
JUMPE 3,.+3
SOUT
ERJMP .+2
JRST [PUSHJ P,ITSBP
MOVE TT,2 ;Rest of code needs updated pointer
JRST WRIBI6]
MOVEM 2,DATBPT(IDX)
MOVNM 3,DATBCT(IDX)
] ;END IFN TNX
HLL C,T ;Save final byte pointer
MOVEM C,DATIOC(IDX) ;Remember total number of bytes in buffer for continuation
IOCERR WRIBI7 ;IOC ERROR, CONTINUATION TO WRIBI7
WRIBI7: MOVE TT,DATBPT(IDX) ;Restore byte pointer, IOC error handler leaves final ptr here
HRRZ C,DATIOC(IDX) ;Restore total number of bytes that were in buffer
HLLZ T,DATIOC(IDX) ;Also restore left half of final byte pointer
;Here after IOC error fixed or after normal completion of output operation
WRIBI6: SETZM DATBPT(IDX) ;Assume no bytes left
IDIV C,DATBPW(IDX) ;Remainder is number of bytes left over in last word
JUMPE D,CPOPJ ;We assumed correctly, no extra words
HRR T,DATBUF(IDX) ;Pointer to buffer
IBP TT ;Point at next byte to go out
MOVE C,(TT) ;Get the last word which has extra bytes in it
MOVEM C,(T) ;Store as first word in buffer
MOVEM T,DATBPT(IDX) ;New byte pointer
MOVEM D,DATBCT(IDX) ;And character count
POPJ P,
;;; Force out any data remaining in the buffer. Called from main program level.
;;; This is -NOT- for continuing from IOC errors, which is done by a different routine.
;;; It is for writing out a residual half-word in binary mode, or for
;;; writing out residual part-word characters in text mode.
WRIFOR: SKIPN T,DATBPT(IDX) ;Any bytes in buffer?
POPJ P, ;Nope, then done right now
MOVE TT,DATSTA(IDX) ;Binary mode?
TLNN TT,ST.BIN
JRST [ MOVE TT,DATBUF(IDX) ;Pointer to beginning of buffer
HRLI TT,440700
MOVE T,DATBCT(IDX) ;Number of bytes now in buffer
JRST WRIFR1 ]
HRRZS T ;Get rid of byte position and size info
MOVE TT,DATBUF(IDX) ;To build byte pointer
HRLI TT,444400
SUBI T,1(TT) ;First calculate actual number of words to SIOT
MOVMS T
WRIFR1:
IFN ITS,[
.CALL [ SETZ
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,TT
%CLIN+%CLEND,,T]
JFCL ;IOC errors will get handled in the wash
MOVEM T,DATBCT(IDX) ;This will be 0 if no IOC error
MOVEM TT,DATBPT(IDX)
JUMPN T,CPOPJ ;If got IOC error, return now
SETZM DATBPT(IDX) ;Else leave pointer zeroed out
POPJ P,
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,TT
MOVN 3,T
JUMPE 3,.+3
SOUT
ERJMP .+2
JRST [SETZM DATBPT(IDX)
POPJ P,]
MOVEM TT,DATBPT(IDX)
MOVNM T,DATBCT(IDX)
POPJ P,
] ;END IFN TNX
;;; Here to send one packet over a data conneciton. IDX is set up. Called with interrupts
;;; off so that the shared packet buffer may be used
REAONE: MOVE A,DATSTA(IDX) ;Get channel state
TLZE A,ST.SYN ;Is a synchronous mark required on this channel?
JRST REASSY ;Yes, send it (ignoring channel state)
JRST @READSP(A) ;Actions to follow depend upon channel state
;Dispatch table
READSP: REACLO ;Channel closed
REAOPN ;Channel open, normal processing
REAASY ;Asynchronous marked (should never happen)
REASYN ;Synchronous marked state
REAEOF ;EOF state
;Channel closed, at eof, or sync or asynch mark. Interrupts shouldn't happen
; Channel cannot stay in synchronous mark state for any amount of time, so this shouldn't
; happen either
REACLO:
REAASY:
REASYN:
REAEOF: AOS (P)
POPJ P,
;Here to send sync mark
REASSY: MOVEI T,CO%SYN ;Synchronous mark opcode
HRRI A,ST%SYN ;Now in sync mark state
PUSHJ P,REAEPK ;Output the packet, but return here
JFCL
PUSHJ P,@DATSYA(IDX) ;Call the routine to process the synchronous mark
MOVEM A,DATSTA(IDX)
POPJ P,
;Here to send an empty packet, opcode is in T
REAEPK: DPB T,[$CPKOP+REAPKT] ;Deposit in packet
SETZ T,
DPB T,[$CPKNB+REAPKT] ;Packet contains no information other than opcode
IFN ITS,[
.CALL [ SETZ
SIXBIT/PKTIOT/
%CLIN,,CHACHN(IDX)
%CLIMM+%CLEND,,REAPKT]
.LOSE %LSSYS
] ;END IFN ITS
IFN TNX,[
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOPKS
MOVEI 3,REAPKT
MTOPR
ERCAL CTLERR
] ;END IFN TNX
MOVEM A,DATSTA(IDX) ;Remember to save new status word
AOS (P) ;Skip return
POPJ P,
;Here when hit EOF. Put channel into EOF state and send EOF packet
REAOEO: HRRI A,ST%EOF ;EOF state
MOVEI T,%COEOF ;Send eof packet
IFN ITS,[
JRST REAEPK
] ;END IFN ITS
IFN TNX,[
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOEOF
MTOPR
ERCAL CTLERR
MOVEM A,DATSTA(IDX)
AOS (P)
POPJ P,
] ;END IFN TNX
;Here to send more data over the data connection
REAOPN: TLNE A,ST.BIN ;Binary mode?
JRST REABIN ;Yes, requires different code
SKIPG DATBCT(IDX) ;Any bytes left in buffer?
PUSHJ P,REABUF ;Nope, fill up buffer
SKIPG T,DATBCT(IDX) ;Did we get any bytes?
JRST REAOEO ;Nope, put channel into EOF state and send an EOF packet
MOVE TT,DATBPT(IDX) ;Pointer into buffer
SETZ BC, ;No bytes in packet
MOVE BP,[441000,,REAPKT+%CPKDT] ;Pointer to start of data in packet
REATXT: ILDB BYTE,TT ;Get next byte from file
TLNN A,ST.RAW ;Raw mode means don't translate
XCT CHR2LM(BYTE) ;Check if any special processing is needed
AOJA BC,REATX0 ;None needed, just output character
JRST REATX1 ;Special processing is done, so just punt the byte
JRST REATX4 ;Skipped twice, a rubout escape.
MOVEI BYTE,"M ;CR, store as M for now in case no LF
IDPB BYTE,BP
ADDI BC,1
SOJLE T,REATX5 ;and absorb following linefeed if any
REATX6: ILDB BYTE,TT
CAIN BYTE,12
JRST [ MOVEI BYTE,215
DPB BYTE,BP
JRST REATX1]
ADD TT,[070000,,] ;Not a line feed, put it back
AOJA T,REATX1 ;Treat stray CR as CRLF
REATX5: PUSHJ P,REABUF ;Get next buffer, first char follows a CR
SKIPG T,DATBCT(IDX)
JRST REATXS ;End of file
MOVE TT,DATBPT(IDX)
JRST REATX6
REATX4: TLNE A,ST.SUI ;Super-image mode means just send rubouts
AOJA BC,[MOVEI BYTE,177 ? JRST REATX0]
SOJLE T,REATX2 ;Jump if end of file-buffer
REATX3: ILDB BYTE,TT ;Get the byte that follows the rubout
XCT CHRQLM(BYTE) ;Convert. Will need no special processing
ADDI BC,1
REATX0: IDPB BYTE,BP ;Store the byte
REATX1: CAML BC,CHPMXC ;Have we written the maximum number of bytes?
SOJA T,REATXS ;Yes, send the packet and return (account for byte as well)
SOJG T,REATXT ;If more characters in buffer just go on
PUSHJ P,REABUF ;Read a new bufferful
SKIPG T,DATBCT(IDX) ;Did we get any more data?
JRST REATXS ;Nope, just send what we have so far
MOVE TT,DATBPT(IDX) ;Else get the byte pointer
JRST REATXT ;And proceed with the transmission
REATX2: PUSHJ P,REABUF ;Get next buffer, first char is quoted with rubout
SKIPG T,DATBCT(IDX)
JRST REATXS ;Oops, end of file in bad place, ignore the stray rubout
MOVE TT,DATBPT(IDX)
JRST REATX3
;Here to store T and TT and send the packet
REATXS: MOVEM T,DATBCT(IDX) ;Save byte count
MOVEM TT,DATBPT(IDX) ;And pointer
JUMPE BC,CPOPJ ;Don't bother transmitting if the packet is null
MOVEI T,CO%TXT ;Data opcode
TLNE A,ST.BIN ;Except if binary mode
TRO T,100 ;This is the correct opcode
DPB T,[REAPKT+$CPKOP]
DPB BC,[REAPKT+$CPKNB]
IFN ITS,[
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIN,,CHACHN(IDX)
%CLIMM+%CLEND,,REAPKT]
.LOSE %LSSYS
] ;END IFN ITS
IFN TNX,[
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOPKS
MOVEI 3,REAPKT
MTOPR
ERCAL CTLERR
] ;END IFN TNX
POPJ P, ;Packet has been transmitted, so return
;Here to read in binary mode
REABIN: HRRZ T,DATBYT(IDX) ;Get byte size
SKIPG DATBCT(IDX) ;If bytes in the buffer
CAIE T,16. ; or if not 16 bit bytes, use slow mode
JRST REABIS
MOVE T,CHPMXW ;Maximum number of words in a packet
MOVE TT,[444400,,REAPKT+%CPKDT]
IFN ITS,[
.CALL [ SETZ ;Read data into the packet
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,TT
%CLIN+%CLEND,,T]
JRST REABI0 ;Ioc error
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,TT
MOVN 3,T ;Negative count is number of bytes we want
SIN
ERCAL REAIOC ;Skips if IOC error as opposed to EOF
SKIPA
JRST REABI0
MOVN T,3
MOVE TT,2
] ;END IFN TNX
CAMN T,CHPMXW ;Did we get any data at all?
JRST REAOEO ;Nope, EOF: send EOF packet, change channel state, and return
MOVE BC,CHPMXW ;Calculate actual number of bytes read
SUBI BC,(T)
LSH BC,2
SETZB T,TT ;Don't get faked into thinking stuff is buffered
JRST REATXS ;Send the packet
;Here on IOC error
REABI0: MOVE B,DATBUF(IDX) ;SAVE PACKET IN IDX BUFFER
MOVEI C,(B) ;COPY FOR TERMINATION CONDITION
HRLI B,REAPKT
BLT B,%CPMXW-1(C) ;SAVE ALL OF PACKET
SUBI C,WRIPKT ;OFFSET FOR BYTE POINTER
ADD TT,C
MOVEM TT,DATBPT(IDX) ;SAVE POINTER
MOVEM T,DATBCT(IDX) ;AND SAVE COUNT
IOCERR REABI1 ;GIVE THE IOC ERROR, CONTINUATION
;IOC error continuation
REABI1: MOVE BC,CHPMXW ;Calculate actual number of bytes read
SUB BC,DATBCT(IDX)
LSH BC,1
MOVEI T,CO%BDT ;Data opcode
DPB T,[REAPKT+$CPKOP]
DPB BC,[REAPKT+$CPKNB]
IFN ITS,[
.CALL [ SETZ
SIXBIT /PKTIOT/
%CLIN,,CHACHN(IDX)
%CLIMM+%CLEND,,DATBUF(IDX)]
.LOSE %LSSYS
] ;END IFN ITS
IFN TNX,[
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOPKS
MOVEI 3,DATBUF(IDX)
MTOPR
ERCAL CTLERR
] ;END IFN TNX
POPJ P, ;Packet has been transmitted, so return
;Slow binary mode. Read block into buffer and use ILDB/IDPB loop to fill packet
REABIS: SKIPG DATBCT(IDX) ;Any bytes left in buffer?
PUSHJ P,REABUF ;Nope, fill up buffer
SKIPG T,DATBCT(IDX) ;Did we get any bytes?
JRST REAOEO ;Nope, put channel into EOF state and send an EOF packet
MOVE TT,DATBPT(IDX) ;Pointer into buffer
SETZ BC, ;No bytes in packet
MOVE BP,[442000,,REAPKT+%CPKDT] ;Pointer to start of data in packet
REABS0: ILDB BYTE,TT ;Get next byte from file
IDPB BYTE,BP ;Store the byte
ADDI BC,2 ;Two more bytes
CAML BC,CHPMXC ;Have we written the maximum number of bytes?
SOJA T,REATXS ;Yes, send the packet and return
SOJG T,REABS0 ;If more characters in buffer just go on
HRRZ T,DATBYT(IDX) ;This 16 bit byte mode?
CAIN T,16.
JRST REABS1 ;Yup, send a small packet and do the rest quickly
PUSHJ P,REABUF ;Read a new bufferful
SKIPG T,DATBCT(IDX) ;Did we get any more data?
JRST REATXS ;Nope, just send what we have so far
MOVE TT,DATBPT(IDX) ;Else get the byte pointer
JRST REABS0 ;And proceed with the transmission
REABS1: SETZB T,TT ;Make sure we go through fast path next time
JRST REATXS
;;; Routine to fill up in-core buffer
;;; Destroy's: B, C, D, T, TT
REABUF: MOVE T,DATBUF(IDX) ;Pointer to the buffer
HRLI T,440700 ;Assume 7 bit bytes
TLNE A,ST.BIN ;Binary mode?
HRLI T,444400 ;Yes, really 36 bit bytes
MOVEM T,DATBPT(IDX) ;Byte pointer if no IOC error
MOVEI TT,2000*5 ;This is correct number of bytes for text mode
TLNE A,ST.BIN ;But is it binary mode?
MOVEI TT,2000 ;Yes, then this is correct byte count
MOVEI B,(TT) ;Count expected maximally
TLNN A,ST.BIN ;Can't have saved word in binary mode
SKIPN D,DATLWD(IDX) ;Do we have a saved last word?
JRST REABF6 ;Nope, proceed normally
SETZM DATLWD(IDX) ;No more last word
MOVEM D,(T) ;Save the word as first buffer word
ADDI T,1 ;Increment pointer
SUBI TT,5 ;Read 5 fewer bytes
REABF6: TLNE A,ST.DIR ;Directory listing?
JRST REDRBF ;Yes, handled specially
IFN ITS,[
.CALL [ SETZ
SIXBIT /SIOT/
%CLIN,,DATCHN(IDX)
%CLIN,,T
%CLIN+%CLEND,,TT]
JRST REABF1 ;IOC error
] ;END IFN ITS
IFN TNX,[
MOVE 1,DATJFN(IDX)
MOVE 2,T
MOVN 3,TT ;Negative count is number of bytes we want
SIN
ERCAL REAIOC ;Skips if IOC error as opposed to EOF, sets up T and TT
SKIPA
JRST REABF1
MOVN TT,3
MOVE T,2
] ;END IFN TNX
REABF3: SUBI B,(TT) ;Actual number of bytes read
TLNN A,ST.BIN ;Binary mode?
JRST REABF4 ;Nope, no special processing
HRRZ D,DATBYT(IDX)
DPB D,[300600,,DATBPT(IDX)] ;Correct size bytes
MOVEI C,36. ;Have number of 36 bit words, need number of real bytes
IDIVI C,(D)
IMULI B,(C) ;Calculate actual number of bytes read
REABF4: MOVEM B,DATBCT(IDX) ;Remember count
IFN TNX,[
POPJ P, ;No need to do trailing control-C checking here
] ;END IFN TNX
IFN ITS,[
SKIPE B ;Return right away if we read nothing
TLNE A,ST.BIN ;If binary mode then done
POPJ P,
IFN ITS,[
;; TT has number of bytes we tried to read, T has pointer to last byte hacked (almost...)
;; Due to gross ITS lossage, check for initial special case of 440700,, and
;; fix it
HLRZ TT,T
CAIN TT,440700
SUB T,[430000,,1]
] ;END IFN ITS
CAIE TT,(B) ;If we got less than we wanted, we hit EOF
JRST READLC
;; We got a full bufferload, but we may have hit EOF! So, must save last word and tack
;; it on next time when we'll know for sure whether we got to EOF
MOVE TT,(T) ;Get the last word
TRO TT,1 ;Force it to be non-zero by setting bit 35 (argghh!)
MOVEM TT,DATLWD(IDX) ;Save the "Last word"
SUBI B,5
MOVEM B,DATBCT(IDX)
POPJ P,
;; Search backwards removing trailing eof chars from the last word
;; T has BP to last byte read, B has count of bytes
READLC: LDB TT,T ;Get last character
CAIE TT,^C
CAIN TT,^L
SOJG B,[ ADD T,[070000,,]
JUMPGE T,READLC
SUB T,[430000,,1]
JRST READLC]
JUMPE B,REABUF ;Get another bufferful if no valid bytes found
MOVEM B,DATBCT(IDX) ;Store number of bytes in buffer
POPJ P, ;Then return
] ;END IFN ITS
REABF1: POP P,DATIOC(IDX) ;Save address of our caller
HRLM B,DATIOC(IDX) ;Also save total number of bytes to be read
MOVEM T,DATBPT(IDX) ;Pointer
MOVEM TT,DATBCT(IDX) ;Remaining bytes to read
IOCERR REABF2
REABF2: PUSH P,DATIOC(IDX) ;Restore adr of our caller
HLRZ B,DATIOC(IDX) ;Total number of bytes expected
MOVE TT,DATBCT(IDX) ;Need bytes left to read
JRST REABF3
IFN TNX,[
REAIOC: MOVE T,2 ;Updated byte pointer
MOVN TT,3 ;Updated count
MOVEI 1,.FHSLF ;Get last error
PUSHJ P,$GETER
JFCL
HRRZS 2 ;Only error number
CAIE 2,IOX4 ;EOF, so non-skip
AOS (P)
MOVE 2,T ;Callers expect these results in 2 and 3
MOVN 3,TT
POPJ P,
$GETER:
IFN 10X,[
PUSH P,4
PUSH P,5
PUSH P,6
PUSH P,7
PUSH P,10
]
GETER
ERJMP .+2
IFN 10X,[
AOS -5(P)
POP P,10
POP P,7
POP P,6
POP P,5
POP P,4
]
.ELSE AOS (P)
POPJ P,
] ;END IFN TNX
;Interrupt table
IFN ITS,[
INTTAB:
LOC 42
-INTLEN,,INTTAB
LOC INTTAB
17,,P
%PIIOC ? 0 ? %PIIOC+%PIDBG+%PIDWN ? 177777 ? IOCINT
%PIDBG ? 0 ? %PIDBG+%PIDWN ? 0 ? DBGINT
%PIDWN ? 0 ? %PIDBG+%PIDWN ? 0 ? DWNINT
REPEAT MAXIDX,[
0 ? 1_<.RPCNT+3> ? %PIDBG+%PIDWN ? 177777 ? CHAINT+<2*.RPCNT>
]
INTLEN==.-INTTAB
;;; Here on receipt of channel interrupt from one of the chaosnet channels.
;;; Figure out which one, and perform the appropriate actions. All AC's saved by system.
;;; All other channel interrupts deffered
CHAINT: MOVEI IDX,0 ;IDX will contain index that got interrupt
JRST CHAIN0
MOVEI IDX,1
JRST CHAIN0
MOVEI IDX,2
JRST CHAIN0
MOVEI IDX,3
JRST CHAIN0
MOVEI IDX,4
JRST CHAIN0
MOVEI IDX,5
; JRST CHAIN0
CHAIN0: PUSHJ P,CHALOP ;Handle this IDX
MOVE T,SSYDF2 ;Cause correct DF2 when dismissed
MOVEM T,-20(P) ;Correct offset: all AC's, the old PC
.CALL [ SETZ
SIXBIT /DISMIS/
%CLBTW,,INTTAB
%CLIN+%CLEND,,P]
.LOSE %LSSYS
;Here with IDX properly set up
CHALOP: .CALL [ SETZ ;Find out why the interrupt happened
SIXBIT /WHYINT/
%CLIN,,CHACHN(IDX)
%CLOUT,,T ;%WYCHA
%CLOUT,,T ;State
%CLOUT+%CLEND,,TT] ;#in packets available ,, #out packets available
.LOSE %LSSYS ;Hmm...
JRST CHAIND(T) ;Dispatch on state
] ;END IFN ITS
;Dispatch table for channel state
CHAIND: JRST CHACLS ;Closed, so close down the channel (protocol violation!!)
JRST CHALSN ;Listen!!
JRST CHARFC ;RFC received!!(!!)
JRST CHARFS ;RFC SENT!!!!!! (This is getting out of hand...)
JRST CHAOPN ;Open ("Better, better")
JRST CHALOS ;Hmm...LOS received
JRST CHAINC ;Incomplete [poor Lisp Machine died....]
CHARFS: POPJ P,
CHALSN:
CHARFC:
CHALOS:
CHAINC:
CHACLS:
;;; Hmmm...Lisp Machine went down or forgot us. Go away if it was a channel in active
;;; use. If not, it is possible that it was a channel that failed to open correctly,
;;; in which case it was just timing out. That's probably ok.
TRZ IDX,1 ;Check input and output
SKIPL DATSTA(IDX)
SKIPGE DATSTA+1(IDX)
PUSHJ P,CTLDON ;If either channel in use, Lisp Machine must have gone away.
JRST CHNFLS ;Flush channels, then return
CHAOPN: TRNE IDX,1 ;Reading or writing?
JRST CHAOPO ;Writing, handle slightly differently
TRNN TT,-1 ;Any output packets available?
POPJ P, ;Nope, then done...just return
PUSHJ P,REAONE ;Handle the packet
JRST CHALOP ;Loop if no error
POPJ P, ;Else return
CHAOPO: TLNN TT,-1 ;Any packets to read?
POPJ P, ;Nope
PUSHJ P,WRIONE
JRST CHALOP
POPJ P, ;Error, return right away
IFN ITS,[
;;; IOC error handler
IOCINT: .SUSET [.RBCHN,,T] ;Get channel that had error
CAIL T,CHALOW
CAILE T,CHAHIG
JRST IOCDAT ;Not CHAOS channel, must be data error
PUSHJ P,CTLDON ;Else something happened to Lisp Machine, we are done
IOCDAT: AOS -17(P) ;Setup to return to location after call which caused error
.CALL [ SETZ
SIXBIT /DISMIS/
%CLBTW,,INTTAB
%CLIN+%CLEND,,P]
.LOSE %LSSYS
;;; System going down and system being debugged inform user then exit to CTLLOP
DBGINT: PUSHJ P,DWNIN1 ;Set up to return notification
MOVEI A,[ASCIZ/system being debugged./]
SKIPN C
MOVEI A,[ASCIZ/system no longer being debugged./]
DWNIN2: PUSHJ P,COMSTO
DWNIN9: .CLOSE ERRCH,
MOVEI T,CO%NOT
PUSHJ P,COMSN1
JRST CTLLOP
DWNIN1: MOVE BP,[441000,,%CPKDT+CTLPKO]
SETZ BC,
.CALL [ SETZ ? 'SSTATU ? MOVEM B ? SETZM C ]
.LOSE %LSSYS
POPJ P,
DWNINT: PUSHJ P,DWNIN1
MOVEI A,[ASCIZ/system revived./]
JUMPL B,DWNIN2
MOVEI A,[ASCIZ/system going down in /]
PUSHJ P,COMSTO
IDIVI B,30.
IDIVI B,60. ;B minutes until down, C seconds
SKIPN A,B
JRST DWNIN3
PUSHJ P,COMDCO
MOVEI A,[ASCIZ/ minutes, /]
PUSHJ P,COMSTO
DWNIN3: MOVE A,C
PUSHJ P,COMDCO
MOVEI A,[ASCIZ/ seconds./]
PUSHJ P,COMSTO
.OPEN ERRCH,[.UAI,,'SYS ? SIXBIT/DOWN/ ? SIXBIT/MAIL/]
JRST DWNIN9
MOVEI BYTE,215
DWNIN4: CAMGE BC,CHPMXC
CAIGE BYTE,40
CAIA
PUSHJ P,COMCHO
.IOT ERRCH,BYTE
JUMPL BYTE,DWNIN9 ;EOF
CAIN BYTE,15
MOVEI BYTE,215
JRST DWNIN4
] ;END IFN ITS
IFN TNX,[
LEVTAB: 0,,PRILE1
0,,PRILE2
0,,PRILE3
CHNTAB: 3,,INTID0 ;Interrupt IDX 0 (channel 0)
3,,INTID1 ;Interrupt IDX 1
3,,INTID2
3,,INTID3
3,,INTID4
3,,INTID5 ;Interrupt IDX 5 (channel 6)
0 ;Arithmetic overflow
0 ;Floating overflow
0 ;Reserved for D.E.C.
1,,CTLERR ;PDL overflow
1,,CTLERR ;EOF
1,,CTLERR ;Data error
1,,CTLERR ;Disk full or quota exceeded
0 ? 0 ;Reserved
1,,CTLERR ;Illegal instruction
1,,CTLERR ;Illegal read
1,,CTLERR ;Illegal write
0 ;Reserved
1,,CTLERR ;Inferior termination or freeze
1,,CTLERR ;System resources exhausted
0 ;Reserved
0 ;Reference to non-existant page
3,,INTID6 ;Interrupt IDX 6 (channel 23.)
3,,INTID7
3,,INTID8
3,,INTID9
3,,INTIDA ;Interrupt IDX 10. (channel 27.)
3,,INTIDB
3,,INTIDC ;IDX 12.
3,,INTIDD ;IDX 13.
3,,INTIDE ;IDX 14.
3,,INTIDF ;IDX 15.
3,,TIMINT ;Timer interrupt
0 ? 0 ;34. and 35. reserved by monitor if
; the job runs at toplevel
INDEX=0
IRPS NAME,,[0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F]
INTID!NAME: JSR LV1SAC ;Save AC's
MOVEI IDX,INDEX
JRST CHAIN0
INDEX=INDEX+1
TERMIN
CHAIN0: PUSHJ P,CHALOP
INTDEB: MOVE 0,[LV1ACS+1,,1]
BLT 0,17
MOVE 0,LV1ACS
DEBRK
;Here with IDX properly set up
CHALOP: MOVE 1,CHAJFN(IDX)
GDSTS ;This gets state in 2, and number of input packets in 3
ERCAL CTLERR
MOVE T,2
HRLZ TT,3
MOVE 1,CHAJFN(IDX)
MOVEI 2,.MOAWS
MTOPR
ERCAL CTLERR
HRR TT,3
JRST CHAIND(T) ;Dispatch on state
;Timer interrupt
TIMINT: JSR LV1SAC
PUSHJ P,TIMIN1
JRST INTDEB ;Dismiss interrupt
;;;Here to initialize the timer
TINTVL==2*60.*1000. ;Every two minutes
TIMRKS: 30. ? 15. ? 10. ? 5. ? 1. ? -30. ;Times at which to notify
TIMIN1: SKIPL TIMINF ;Ok for timer interrupt?
JRST [ AOS TIMINF ;No, note that one went off
JRST SETTIM] ;And skip downtime check for now
PUSHJ P,DWNCHK
JRST SETTIM
DWNCHK:
IFN 10X,MOVE 1,[SIXBIT /SYSTAT/]
.ELSE MOVE 1,[SIXBIT /DWNTIM/]
SYSGT
HRRZ A,2 ;Table number
MOVE 1,A
IFN 10X,HRLI 1,27
GETAB
SETZ 1,
JUMPE 1,NODWNT
MOVE C,1
GTAD
SUB C,1 ;Get time until shutdown
TLNE C,-1 ;More than a day?
JRST NODWNT
IFN 10X,IDIVI C,60. ;Into minutes
.ELSE [
IMULI C,24.*60.
HLRZS C
]
SETZ D,
CAMG C,TIMRKS(D) ;Find range of time
AOJA D,.-1
JUMPE D,NODWNT ;More than maximum time
CAMN D,DWNTIM ;Same as last notification?
POPJ P, ;Yes
MOVEM D,DWNTIM
IFN 10X,SETOM DWNTIM+1
PUSHJ P,DWNIN1
MOVEI A,[ASCIZ /system going down in /]
PUSHJ P,COMSTO
MOVE A,C
PUSHJ P,COMDCO
MOVEI A,[ASCIZ / minute/]
PUSHJ P,COMSTO
MOVEI BYTE,"s
CAIE C,1
PUSHJ P,COMCHO
MOVEI BYTE,".
PUSHJ P,COMCHO
JRST DWNIN2
NODWNT: SKIPN DWNTIM
POPJ P,
IFN 10X,[
AOSN DWNTIM+1 ;Tenex cancels shutdown just before shutting down
POPJ P, ;So don't say it's cancelled until it's cancelled twice
];10X
SETZM DWNTIM
PUSHJ P,DWNIN1 ;Set up to return notification
MOVEI A,[ASCIZ/shutdown cancelled./]
PUSHJ P,COMSTO
DWNIN2: MOVEI T,CO%NOT
JRST COMSN1
DWNIN1: MOVE BP,[441000,,%CPKDT+CTLPKO]
SETZ BC,
POPJ P,
;; Setup timer interrupt
SETTIM:
IFN 20X,[
MOVE 1,[.FHSLF,,.TIMEL] ;Tick the timer
MOVE 2,[TINTVL]
MOVEI 3,33. ;On channel 33
TIMER
JFCL
];IFN 20X
.ELSE [
IFNDEF IIT,IIT=JSYS 630
MOVEI 1,.FHSLF ;This fork
MOVEI 2,4 ;On channel 33.
MOVE 3,[TINTVL]
IIT ; Set to trigger it
];10X
POPJ P,
;;; Print the contents of a Chaosnet packet. A has the byte-count,
;;; and B a BP to the data area.
IFN $$LOG,[
PktPrt: Move 1,TriJFN
Movei 2,^I
BOUT
Setz 3,
PP0:: Sojl A,PP1
Ildb 2,B
Cain 2,215
Jrst [Hrroi 2,[Asciz "<NL>"]
SOUT
Jrst PP0]
BOUT
Jrst PP0
PP1: Hrroi 2,[Asciz "<EOP>
"] ? SOUT
Popj P,
];$$LOG
];END IFN TNX
;;; Character translation tables
;Byte is a pdp10 character to be sent to Lisp machine.
;This table used when not preceded by rubout escape.
;Skip once to ignore it, twice if this is rubout escape, three times for CR.
CHR2LM: REPEAT 10, JFCL ;0 through 7, leave alone
REPEAT 3, ADDI BYTE,200 ;10 through 12 turn into backspace, tab, linefeed
JFCL ;13 stays as uparrow
ADDI BYTE,200 ;14 form
JSP BYTE,[JRST 3(BYTE)] ;15 skip three times for carriage return
REPEAT 177-16, JFCL ;16-176 unchanged
JSP BYTE,[JRST 2(BYTE)] ;177 skip twice for quoting special character
IFN .-CHR2LM-200, .ERR CHR2LM table not 200 long
;This table used when preceded by rubout escape.
CHRQLM: REPEAT 10, ADDI BYTE,200 ;0-7 => 200-207
REPEAT 3,JFCL ;10-12 self
ADDI BYTE,200 ;13 => 213
REPEAT 2, JFCL ;14, 15 self
REPEAT 177-16, ADDI BYTE,200 ;16-176 => 216-376
JFCL ;177 self
IFN .-CHRQLM-200, .ERR CHRQLM table not 200 long
;BYTE is a lisp-machine character to be put into pdp10 buffer via BP and BC
;Skip to ignore it.
CHR210: REPEAT 10, JFCL ;0 through 7, leave alone
REPEAT 3, PUSHJ P,CHRQ10 ;10, 11, 12 hidden under backspace, tab, lf
JFCL ;13 stays as uparrow
REPEAT 2, PUSHJ P,CHRQ10 ;14, 15 hidden under form, cr
REPEAT 177-16, JFCL ;No change to 16 through 176
REPEAT 11, PUSHJ P,CHRQ10 ;177-207 quoted
REPEAT 3, SUBI BYTE,200 ;Scale down to PDP-10 equivalents for 210 - 212
PUSHJ P,CHRQ10 ;213 quoted
SUBI BYTE,200 ;Scale down to PDP-10 equivalent for 214
PUSHJ P,[MOVEI BYTE,15 ;Insert <CR><LF> for newline
IDPB BYTE,BP
ADDI BC,1
MOVEI BYTE,12
POPJ P,]
REPEAT 377-216, PUSHJ P,CHRQ10 ;216-376 quoted
SKIPA ;377 ignored
IFN .-CHR210-400, .ERR CHR210 table not 400 long
CHRQ10: TLNE A,ST.SUI ;Super-image mode
POPJ P, ;Just output byte with no quoting in super-image mode
HRLM BYTE,(P) ;Output this byte preceded by 177 to quote it
MOVEI BYTE,177
IDPB BYTE,BP
ADDI BC,1
HLRZ BYTE,(P)
POPJ P,
;Error code table
IFN ITS,[
ERRTAB: %ERODV,,'ACC ;ACCESS ERROR--DEVICE WRITE-LOCKED
%ELCDV,,'ACC ;ACCESS ERROR--LOCAL DEVICE ONLY
%EMCHN,,'ACC ;ACCESS ERROR--DEVICE NOT ASSIGNABLE TO THIS PROCESSOR
%ETMDR,,'CCD ;CANNOT CREATE DIRECTORY--MFD FULL
%ETMLK,,'CIR ;CIRCULAR LINK
%ETMTR,,'CIR ;CIRCULAR "LINK"--TOO MANY TRANSLATIONS
%ENSDV,,'DEV ;DEVICE NOT FOUND
%ENSDR,,'DNF ;DIRECTORY NOT FOUND
%ENSFL,,'FNF ;FILE NOT FOUND
%ENAFL,,'LCK ;FILE LOCKED
%EBDLK,,'LNF ;LINK TO NONEXISTENT FILE
%ENRDV,,'NAV ;EXISTS BUT NOT AVAILABLE--DEVICE NOT READY
%ENAPK,,'NAV ;--PACK NOT MOUNTED
%ENADV,,'NAV ;--DEVICE NOT AVAILABLE
%ENACR,,'NER ;NOT ENOUGH RESOURCES--NO CORE AVAILABLE
%EFLDR,,'NMR ;NO MORE ROOM--DIRECTORY FULL
%EFLDV,,'NMR ;NO MORE ROOM--DEVICE FULL (SHOULD BE NER SOMETIMES!)
%EEXFL,,'REF ;RENAME TO EXISTING FILE
%ENSMD,,'WKF ;WRONG KIND OF FILE--MODE NOT AVAILABLE
%EBDDV,,'WKF ;WRONG KIND OF DEVICE
;IOC errors. These don't seem to have symbolic names.
1000,,'MSC ;DEVICE HUNG OR REPORTING NON-DATA ERROR
2000,,'FOR ;END OF FILE
3000,,'DAT ;NON-RECOVERABLE DATA ERROR
4000,,'DEV ;NON-EXISTENT SUB-DEVICE (?)
;5000,,'BUG ;OVER IOPOP
;6000,,'BUG ;OVER IOPUSH
7000,,'WKF ;USR OP CHNL DOES NOT HAVE USR OPEN
;10000,,'BUG ;CHNL NOT OPEN
11000,,'NMR ;DEVICE FULL
12000,,'WKF ;CHNL IN ILLEGAL MODE ON IOT
13000,,'DAT ;ILLEGAL CHR AFTER CNTRL P ON TTY DISPLAY (?)
14000,,'NMR ;DIRECTORY FULL
LERRTB==.-ERRTAB
];ITS
IFN TNX,[
ERRTAB: GJFX29,,'ACC ;ACCESS ERROR--DEVICE NOT AVAILABLE TO THIS JOB
ACESX7,,'ACC ;ACCESS ERROR--DIRECTORY IS FILES-ONLY
CFDBX2,,'ACC ;ACCESS ERROR--INVALID TO CHANGE SPEC'D BITS
CFDBX3,,'ACC ;ACCESS ERROR--WRITE OR OWNER ACCESS REQUIRED
CRDIX1,,'ACC ;ACCESS ERROR--WHEEL/OPERATOR REQUIRED
DELFX1,,'ACC ;ACCESS ERROR--DELETE ACCESS REQUIRED
OPNX12,,'ACC ;--LIST ACCESS REQUIRED
OPNX25,,'ACC ;--DEVICE WRITE-LOCKED
CAPX1,,'ACC ;--WHEEL/OPERATOR
CAPX2,,'ACC ;--WHEEL/OPERATOR/MAINTENANCE
DELDX1,,'ACC ;--WHEEL/OPERATOR
WHELX1,,'ACC ;--WHEEL/OPERATOR
GTDIX1,,'ACC ;--WHEEL/OPERATOR
MTOX7,,'ACC ;--WHEEL/OPERATOR
CNDIX2,,'ACC ;--WHEEL/OPERATOR
IFDEF ACJX01,[ ;MIT addition: access control job
ACJX01,,'ACC
]
GJFX35,,'ATD ;INCORRECT ACCESS TO DIRECTORY
ACESX3,,'ATD ;INCORRECT ACCESS TO DIRECTORY--PASSWORD REQUIRED
OPNX3,,'ATF ;ACCESS TO FILE--READ
OPNX4,,'ATF ;ACCESS TO FILE--WRITE
OPNX5,,'ATF ;ACCESS TO FILE--EXECUTE
OPNX6,,'ATF ;ACCESS TO FILE--APPEND
OPNX15,,'ATF ;ACCESS TO FILE--READ/WRITE
RNAMX3,,'ATF ;ACCESS TO FILE--RENAME DESTINATION
RNAMX8,,'ATF ;ACCESS TO FILE--RENAME SOURCE
CRDI10,,'CCD ;CANNOT CREATE DIR--MAX DIR NUM EXCEEDED
CRDI13,,'CCD ;--EXCEEDS WORKING QUOTA
CRDI14,,'CCD ;--EXCEEDS PERMANENT QUOTA
CRDI15,,'CCD ;--EXCEEDS SUBDIRECTORY QUOTA
CRDI16,,'CCD ;--INVALID USER GROUP
CRDI17,,'CCD ;--ILLEGAL LOGIN SUBDIR UNDER FILES-ONLY
CRDI20,,'CCD ;--CANNOT CREATE DIR WITH NOT-HELD CAPABILITY
CRDI21,,'CCD ;--WORKING SPACE TOO SMALL
CRDI22,,'CCD ;--SUBDIR QUOTA TOO SMALL
CRDI24,,'CCD ;--INVALID SUBDIR QUOTA
CRDIX4,,'CCD ;--SUPERIOR DIRECTORY FULL
IFDEF CRDX01,[ ;MIT addition: more CRDIR errors with inconsistent names
CRDX01,,'CCD ;--SUPERIOR MAY NOT HAVE LOGIN SUBDIRECTORIES
CRDX02,,'CCD ;--CREATE-LOGIN-SUBDIRECTORIES CAP REQUIRED
CRDX03,,'CCD ;--DIRECTORY MUST BE FILES-ONLY
];CRDX01
SFUSX6,,'CSP ;CAN'T SET PROPERTY--NO SUCH USER
GJFX39,,'CIR ;CIRCULAR "LINK"--LOGICAL NAME LOOP
CRDIX2,,'DAE ;DIR ALREADY EXISTS--ILLEGAL TO CHANGE DIR NUMBER
IOX5,,'DAT ;DATA ERROR
OPNX16,,'DAT ;DATA ERROR--INDEX BLOCK BAD
GJFX16,,'DEV ;DEVICE NOT FOUND
DELX13,,'DND ;DONT-DELETE SET--PERPETUAL
GJFX17,,'DNF ;DIRECTORY NOT FOUND
CRDI23,,'DNF ;SUPERIOR DIRECTORY NOT FOUND (CRDIR)
GJFX27,,'FAE ;FILE ALREADY EXISTS
GJFX18,,'FNF ;FILE NOT FOUND--NO SUCH NAME
GJFX19,,'FNF ;FILE NOT FOUND--NO SUCH TYPE
GJFX20,,'FNF ;FILE NOT FOUND--NO SUCH VERSION
GJFX24,,'FNF ;FILE NOT FOUND
GJFX52,,'FNF ;FILE NOT FOUND--END OF TAPE REACHED WHILE SEARCHING
OPNX2,,'FNF ;FILE NOT FOUND--DOES NOT EXIST
GJFX10,,'IPS ;INVALID PATHNAME SYNTAX--NON-NUMERIC VERSION
GJFX11,,'IPS ;--MORE THAN ONE VERSION NUMBER
GJFX33,,'IPS ;--FILENAME NOT SPECIFIED
GJFX4,,'IPS ;--INVALID CHARACTER
GJFX6,,'IPS ;--DEVICE FIELD MISPLACED
GJFX7,,'IPS ;--DIRECTORY FIELD MISPLACED
GJFX8,,'IPS ;--GREATER THAN MISPLACED
GJFX9,,'IPS ;--MORE THAN ONE NAME
GJFX40,,'IPS ;--UNDEFINED ATTRIBUTE
GJFX5,,'IPS ;--FIELD LONGER THAN 39 CHARS
CFDBX4,,'IPV ;INVALID PROPERTY VALUE
LGINX4,,(SIXBIT/IP?/) ;INVALID PASSWORD
CRDIX6,,'LCK ;FILE LOCKED--DIRECTORY FILE IS MAPPED
CRDIX7,,'LCK ;--FILES OPEN IN DIR
CRDI18,,'LCK ;--LOGIN DIR
CRDI19,,'LCK ;--CONNECTED DIR
OPNX9,,'LCK ;--INVALID SIMULTANEOUS ACCESS
RNMX10,,'LCK ;FILE LOCKED--RENAME SOURCE IS OPEN
LGINX1,,'LIP ;LOGIN PROBLEM--INVALID ACCOUNT
LGINX2,,'LIP ;--FILES-ONLY
LGINX3,,'LIP ;--DIRECTORY FUKT
GJFX28,,'NAV ;NOT AVAILABLE--DEVICE NOT ONLINE
OPNX7,,'NAV ;--ASSIGNED TO OTHER JOB
OPNX8,,'NAV ;--NOT ONLINE
DELX11,,'NAV ;--CAN'T DELETE WHEN ARCHIVED
OPNX30,,'NAV ;--CAN'T OPEN WHEN ARCHIVED
OPNX31,,'NAV ;--FILE OFFLINE
CRDI12,,'NAV ;STRUCTURE IS NOT MOUNTED
IFDEF IOX35,[ ;20X Release 5 addition
IOX35,,'NAV ;Disk structure damaged--cannot allocate space
];IOX35
LGINX6,,'NER ;NOT ENOUGH RESOURCES--NO JOB SLOTS
CRDIX3,,'NER ;NOT ENOUGH RESOURCES--JSB FULL
OPNX17,,'NER ;NOT ENOUGH RESOURCES--NO ROOM FOR LONG FILE PAGE TABLE
GJFX22,,'NER ;NOT ENOUGH RESOURCES--JSB FULL
GJFX3,,'NER ;NOT ENOUGH RESOURCES--NO JFN SLOTS
ACESX2,,'NER
IOX12,,'NER ;--SWAP SPACE FULL
MONX01,,'NER
MONX02,,'NER ;--JSB FULL
MONX04,,'NER ;--SWAP SPACE FULL
MONX05,,'NER ;--NO RESIDENT FREE SPACE
RNMX13,,'NER
GJFX23,,'NMR ;NO MORE ROOM--DIRECTORY FULL
IOX11,,'NMR ;NO MORE ROOM--QUOTA EXCEEDED OR DISK FULL
OPNX10,,'NMR ;NO MORE ROOM--STRUCTURE FULL
OPNX23,,'NMR ;NO MORE ROOM--QUOTA EXCEEDED
RNAMX4,,'NMR ;NO MORE ROOM--QUOTA EXCEEDED IN RENAME DESTINATION
IFDEF IOX34,[ ;20X Release 5 addition
IOX34,,'NMR ;Disk structure completely full
];IOX34
RNAMX1,,'RAD ;RENAME ACROSS DIRECTORIES--ACROSS DEVICES ACTUALLY
RNMX12,,'REF ;RENAME TO EXISTING FILE--SELF
RNAMX2,,'REF ;--FILE NOT CLOSED
GJFX38,,'WKF ;WRONG KIND OF FILE--OUTPUT-ONLY DEVICE
OPNX13,,'WKF ;--"INVALID ACCESS REQUESTED" (Read of a dir gives this)
OPNX14,,'WKF ;--"INVALID MODE REQUESTED"
GJFX31,,'WNA ;WILDCARD NOT ALLOWED--INVALID WILDCARD DESIGNATOR
GJFX34,,'WNA ;--INVALID QUESTION MARK
LERRTB==.-ERRTAB
];TNX
0,,'BUG ;If run off end of table
PAT:
PATCH: BLOCK 100
;;; Start here to install
PURIFY: SETZM DEBUG
IFN ITS,[
MOVE T,[-<PURPND-NIMPUR>,,NIMPUR]
.CALL [ SETZ ? 'CORBLK ? MOVEI %CBNDR ? MOVEI %JSELF ? T ? SETZI %JSELF ]
.LOSE %LSSYS
.VALUE [ASCIZ/:PDUMP DSK:DEVICE;CHAOS FILE/]
];END IFN ITS
IFN TNX,[
HLRO 1,JOBSYM ;Find end of symbol table
MOVNS 1
ADD 1,JOBSYM
HRRZS 1
CAIG 1,PURPND*1000
JRST PURIF1
HRROI 1,[ASCIZ/Not enough space left for symbol table/]
PSOUT
HALTF
PURIF1: MOVEI 1,.FHSLF
MOVE 2,[1,,FILE]
SEVEC
SETOB 2,3
EPCAP
MOVSI 1,(GJ%SHT+GJ%FOU+GJ%NEW)
RADIX 10.
IFN 20X,HRROI 2,[CONC [ASCIZ /SYSTEM:CHAOS.FILE.],\.FVERS,/]
IFN 10X,HRROI 2,[CONC [ASCIZ /DSK:<SYSTEM>CHAOS.FILE;],\.FVERS,/]
RADIX 8
GTJFN
HALTF
HRLI 1,.FHSLF
MOVEI 2,[ -NIMPUR,,520000 ;Low impure copy on write
-<PURPND-NIMPUR>,,120000+NIMPUR ;Pure pages
0 ] ;End
SSAVE
HRROI 1,[ASCIZ/Saved.
/]
PSOUT
HALTF
] ;END IFN TNX
CONSTANTS
IFN ITS,[
MFDBUF==:.\1777+1
PURPND==:MFDBUF/2000
DIRBUF==:MFDBUF+2000
BUFBAS==:<DIRBUF+2000>/2000
];END IFN ITS
IFN TNX,[
PURPND==:<<.+777>/1000>+NSYMPG
IFN $$SUBM,[
QSRPAG==:PURPND
QSRLOC==:QSRPAG*1000
BUFBAS==:<QSRLOC+1777>/2000
];$$SUBM
.ELSE BUFBAS==:<PURPND*1000+1777>/2000
];TNX
BUFLOC==:BUFBAS*2000
PURLOC==.
LOC IMPLOC
VARIABLES
IMPLOC==.
IFG .-PURBEG,[
INFORM Impure is ,\<.-PURBEG>, words too long!
.FATAL Too much impure, increase NIMPUR
]
IF2,[
INFORM END OF IMPURE=,\IMPLOC
INFORM START OF PURE=,\PURBEG
INFORM END OF PURE=,\PURLOC
IFN TNX,[
IFN $$SUBM,[
INFORM QUASAR IPCP LOC=,\QSRLOC
];$$SUBM
];TNX
INFORM FIRST BUFFER LOC=,\BUFLOC
];IF2
IFN TNX, LOC PURLOC ;SEEMS TO CONTROL SYMBOL TABLE LOCATION
END FILE