Google
 

Trailing-Edge - PDP-10 Archives - cuspjul86upd_bb-jf24a-bb - 10,7/decmai/mx/mxut10.mac
There are 11 other files named mxut10.mac in the archive. Click here to see a list.
	TITLE	MXUT10
	SEARCH	UUOSYM,ACTSYM,MACTEN,UFDPRM
;	Miscellaneous functions for MX

	.TEXT	",REL:UFDSET/SEGMENT:LOW"

	TWOSEG
	RELOC	400000
;	External references

	EXTERN	UM%GET		;MX's memory get routine

;	Define some ACs

	T1=1
	T2=T1+1
	T3=T2+1
	T4=T3+1
	P1=5
	P2=P1+1
	P3=P2+1
	P4=P3+1
	P5=P4+1
	P=17

	QUOTE==42		;ASCII VALUE OF QUOTE CHARACTER

;DATA AREA
	RELOC	0

PRTBLK:	XWD 1,.STDPC		;Set default protection for job(SETPRO)
PRTBL1: 0			;The default file protection

TRMBLK:	BLOCK	3		;TRMOP. BLOCK(SPLTTY & Friends)

MAIFLG:	BLOCK	1		;Anti-recursion flag (NAMPPN/PPNNAM)
NAMPTR: BLOCK	1		;Saved copy of the name to lookup (T1)
MAIBUF: BLOCK	20		;MAILING ADDRESS BUFFER...
QUEARG:	BLOCK	10		;QUEUE. ARG BLOCK
QUERSP:	BLOCK	1000		;QUEUE. RESPONSE BLOCK (This should do)

FLPBLK:	BLOCK 	.FOFSP		;(QUOTAS)
LKPBLK:	BLOCK	.RBUSD+1

BLDSAV:	BLOCK	3		;SAVE AREA FOR ACS 14-16 (BLDQUE)
BLDING:	Z			;NONZERO INDICATES REBUILD OF QUEUE IN PROGRESS

ERRFLG:	BLOCK	1		;NON-ZERO IF AN ERROR OCCURED (UFDCRE/UFDDEL)
FUNCT:	BLOCK	1		;FUNCTION CODE
AUXPTR:	BLOCK	1		;AOBJN POINTER TO STRUCTURES
USRPPN:	BLOCK	1		;USER PPN
PROFIL::BLOCK	1		;ADDRESS OF PROFILE (GLOBAL for MXUFDE)
UFDBLK:	BLOCK	.UFSIZ		;UFDSET ARGUMENT BLOCK

	RELOC	400000
;SETPRO	-sets the default protection of UPS: files.
;
;	CALL SETPRO
;
;Returns +1 always.
SETPRO::
	MOVE	T1,[F%FDAE&<-1,,0>!.GTFET] ;GETTAB ARGS
	GETTAB	T1,			;NEED TO KNOW IF MONITOR
	  SETZ	T1,			; SUPPORTS A FILE DAEMON
	MOVEI	T2,077			;FILE PROTECTION IF NO FILDAE
	TXNE	T1,F%FDAE&<0,,-1>	;FILDAE MONITOR?
	TRO	T2,400			;YES
	MOVEM	T2,PRTBL1		;Store it in the argument block
	MOVE	T1,[XWD .STDEF,PRTBLK]	;.STDEF set default function for SETUUO
	SETUUO	T1,			;Do it
	  JRST 	.+1			;Don't care
	POPJ	P,

;FNDUSR	- returns the next logged in job of a specific PPn
;
;	MOVE	T1,PPn
;	MOVX	T2,0 or last job number of PPn
;	PUSHJ	P,FNDUSR
;	  returns here if ppn has no more logged in jobs
;	returns here with next job # in T2
;
;	USES	T3,T4

FNDUSR::MOVX	T3,%CNSJN	;GET MAXIMUM NUMBER OF JOBS
	GETTAB	T3,		;FROM THE MONITOR
	  SETZ	T3,		;SHOULD NEVER HAPPEN
	HRRZS	T3		;GET THE MAXIMUM
FNDUS1:	AOS	T2 		;MOVE ON TO THE NEXT JOB
	CAMLE	T2,T3		;ARE THERE ANY MORE JOBS?
	  POPJ	P,		;NOPE, RETURN
	MOVX	T4,.GTPPN	;GET THE PPN
	HRL	T4,T2		;FOR THIS NEXT JOB
	GETTAB	T4,		;FROM THE MONITOR
	  JRST	FNDUS1		;(SHOULD NEVER HAPPEN) DO THE NEXT JOB
	CAME	T4,T1		;ARE THEY THE SAME
	  JRST	FNDUS1		;NO, THEN SKIP THIS
	JRST	CPOPJ1		;YES, SKIP RETURN


	SUBTTL	SPLCHR - SPLAT A CHARACTER TO A TERMINAL (VERY SLOW)

; We probably do NOT want to use this!



SPLCHR:	MOVEM	T1,TRMBLK+2	;SAVE IT IN THE BLOCK
	MOVX	T1,.TOOUC	;TYPE OUT A CHARACTER
	MOVEM	T1,TRMBLK	;SAVE IT
	MOVE	T1,[XWD 3,TRMBLK]	;LEN,,ADDRESS
	TRMOP. T1,		;DO IT
	  JFCL
	POPJ	P,		;RETURN WHEN DONE

	SUBTTL	SPLTTY - SPLAT a message across someones TTY if he has one

;SPLTTY	Splats a message across a specific jobs terminal
;
;	MOVEI	T1,message address
;	MOVE	T2,job number
;	PUSHJ	P,SPLTTY
;	  returns here always
;
;	USES	T1,T3

SPLTTY::HRRZ	T3,T2		;DON'T DESTROY THE JOB NUMBER
	TRMNO.	T3,		;GET THE TERMINAL NUMBER
	  POPJ	P,		;SPLAT RETURN AFTER POP
	MOVEM	T3,.TOUDX+TRMBLK ;GET IT IN THE TRMOP. BLOCK
	PUSHJ	P,CHKSND	;DOES HE CARE?
	  POPJ	P,		;NO, THEN FORGET ABOUT HIM
	MOVEM	T1,.TOAR2+TRMBLK ;MESSAGE TO BE SPLATTED
	MOVX	T1,.TODSP	;DISPLAY FUNCTION
	MOVEM	T1,TRMBLK	;SAVE IT
	MOVE	T1,[XWD 3,TRMBLK] ;FUNCTION IS DISPLAY
	TRMOP.	T1,		;SPLAT IT TO HIM
	  POPJ	P,		;OH WELL, DIDN'T MAKE IT MUST BE DETACHED
	POPJ	P,		;RETURN

	SUBTTL	CHKSND - See if he really wants to know about it

; T2/ Job number	uses T3


CHKSND:	MOVS	T3,T2		;GET THE JOB NUMBER
	HRRI	T3,.GTLIM	;GET THE TIME LIMIT WORD
	GETTAB	T3,		;GET THE INFO
	  JRST	CHKSN1		;FIGURE HE'S NOT BATCH
	TXNE	T3,JB.LBT	;IS IT ON?
	  POPJ	P,		;YES, THEN SKIP THIS STUFF
CHKSN1:	MOVX	T3,.TOSND	;GET THE FUNCTION CODE
	MOVEM	T3,TRMBLK	;FOR THE TTY
	MOVE	T3,[XWD 2,TRMBLK] ;LEN,,ADDRESS
	TRMOP. T3,		;DO IT
	  POPJ  P,		;RETURN TO CALLER
	TXNE	T3,1B35		;IS THIS GAGGED?
	  JRST	CPOPJ1		;SKIP RETURN
	POPJ	P,		;RETURN IF YES

;NAMPPN - TRANSLATE USERID NAME STRING INTO PPN FROM ACTDAE
;PPNNAM - TRANSLATE PPN INTO USERID NAME STRING FROM ACTDAE
;CALL IS:
;
;	MOVX	T1,<PTR>	MOVX	T1,<PTR2>
;	PUSHJ	P,NAMPPN   or	PUSHJ 	P,PPNNAM
;	 error return		  error	return
;	normal return		normal	return
;
;<PTR> is an eight bit byte pointer to the beginning of the username
;string (with any leading bracket trimmed) and ending in a null.
;<PTR2> is a pointer to a word containing the PPN to be traslated.
;
;On error return, no name match could be found, or <PTR> was no eight bit
;string.
;
;On normal return, T1 will contain the ppn or a pointer to the 8-bit username.
;
;	USES	T1-T4


NAMPPN::MOVEM	T1,NAMPTR	;Save the name in case of mail forwarding error
	SETZM	MAIFLG		;Initialize the Anti-recursion flag
NAMPP1:	MOVE	T3,[^D10,,.UGUSR] ;USERNAME DESCRIPTOR FOR QUEUE.
	PUSHJ	P,ACTCOM	;SET UP GENERIC ACTDAE CALL
	  JRST	[MOVE	T1,MAIFLG	;Get the forwarding flag
		CAIN	T1,0		;Was this for a forwarding address?
		POPJ	P,		;No.  Return now...
		MOVE	T1,[POINT 7,QUERSP] ;Yes. Frwrding failed.
		PUSHJ	P,MXUFDE	;Log it.
		MOVE	T1,NAMPTR	;Restore the original name
		SETZM	NAMPTR		;Clear it
		CAIE	T1,0		;Was it zero?
		JRST	NAMPP1		;No. Go get the original profile
		POPJ	P,]		;Yes. I've done this before. Return now
	MOVE	T1,QUERSP+.AEMAI;Get the pointer to the mailing address
	CAIE	T1,0		;Skip if zero
	JRST	GETMAI		;Go process the mailing address
NAMPP2:	HRRZ	T1,QUERSP	;Get the size of the profile for UM%GET
	ADDI	T1,1		;Include the first word
	PUSH	P,T1		;Pass it to...
	PUSHJ	P,UM%GET	;...the memory get routine
	ADJSP	P,-1		;Clean up the stack: T1 contains the address
	SKIPG	T1		;Is there an address here?
	  POPJ	P,		;  Too bad, no memory
	HRLI	T3,QUERSP	;Source = QUERSP
	HRR	T3,T1		;Destination = address from UM%GET
	HRRZ	T2,QUERSP	;Get the size of the profile for the BLT
	ADD	T2,T1		;Point to the last word
	BLT	T3,-1(T2)	;Copy the profile

	JRST	CPOPJ1		;AND RETURN HAPPY

GETMAI:	MOVE	T2,MAIFLG	;Get the mail flag
	CAIE	T2,0		;Is it zero?
	JRST	NAMPP2		;No, we've got a valid profile.
	MOVEI	T2,1		;Set the MAIFLG...
	MOVEM	T2,MAIFLG	;...so we won't do this again.
	HLRE	T3,T1		;Negative count is now in T3
	MOVN	T3,T3		;Positive count is now in T3
	ADDI	T1,QUERSP	;Add the base to the offset
	HRLZ	T1,T1		;Source is in LH
	HRRI	T1,MAIBUF	;Destination is in RH
	BLT	T1,MAIBUF(T3)	;Copy it
	MOVE	T1,[POINT 8,MAIBUF] ;build an 8-bit pointer to the name
	MOVE	T2,T1		;Make a copy of the pointer
	ILDB	T3,T2		;Get the first byte
	CAIN	T3,"["		;Is it a square bracket
	JRST	NAMPP2		;Yes.  We don't handle PPN's
	CAIN	T3,QUOTE	;Is it a quote?
	JRST	NAMPP2		;Yes, we don't handle quoted strings
NODLUP:	CAIN	T3,":"		;Is it a colon?
	JRST	NAMPP2		;Yes. We don't handle remote addresses
	CAIN	T3,0		;Is it a null?
	JRST	NAMPP1		;Yes, Get the new profile
	ILDB	T3,T2		;No.  Get the next byte,
	JRST	NODLUP		;...and keep looking.
	
PPNNAM::MOVE	T3,[1,,.UGPPN] ;PPN DESCRIPTOR FOR QUEUE.
	PUSHJ	P,ACTCOM	;DO ACTDAE CALL
	  POPJ	P,		;NO SUCH PPN
	MOVEI	T1,QUERSP+.AENAM ;GET THE USERNAME RETURNED
	JRST	CPOPJ1		;AND HAPPY LANDINGS

ACTCOM:	MOVEI	T4,QUEARG-1	;POINT AT THE ARGUMENT BLOCK STORAGE
	PUSH	T4,[QF.RSP!.QUMAE] ;SAY WE WANT TO TALK TO ACTDAE
	PUSH	T4,[-1]		;SET THE NODE TO CENTRAL
	MOVEI	T2,QUERSP	;POINT AT THE RESPONSE STORAGE
	HRLI	T2,1000		;GET THE NUMBER OF WORDS WE CAN PLAY WITH HERE
	PUSH	T4,T2		;PUT IN THE ARG BLOCK
	PUSH	T4,[QA.IMM!<1,,.QBAFN>] ;GET THE SUBFUNCTION ARGUMENT TYPE
	PUSH	T4,[EXP UGOUP$]	;SAY WE WANT THE USER PROFILE
	PUSH	T4,T3		;STORE THE USERNAME OR PPN DESCRIPTOR
	PUSH	T4,T1		;STORE THE USERNAME OR PPN POINTER
	ANDI	T4,-1		;GET RID OF JUNK IN THE LEFT HALF
	SUBI	T4,QUEARG	;COMPUTE THE NUMBER OF WORDS WE FILLED IN
	MOVEI	T1,QUEARG	;POINT AT THE ARGUMENT BLOCK
	HRL	T1,T4		;COPY THE BLOCK LENGTH
	QUEUE.	T1,		;ASK FOR THE PPN FOR THIS GUY
	 POPJ	P,		;WELL, WE GAVE OUR ALL
	JRST	CPOPJ1		;SUCCESSFUL RETURN
;NOTE
;
;To validate a username (what are you REALLY trying to do?) use NAMPPN.  You
;will probably want to cache the usernames because doing the QUEUE. is VERY,
;VERY, VERY slow!  Note also that the User Name is in *8*bit!
; T1=-1 OR UDT TO CONVERT  UDTDAT-DATE & TIME; DATTIM-TIME ONLY
; T2=ADDRESS WHERE TO PLACE DATE-TIME; USES T1-T4,P1-P5


UDTDAT::TDZA	P1,P1			;USE FOR FLAG THAT DATE IS WANTED
UDTTIM::SETO	P1, 			;-1 MEANS TIME ONLY
	CAME	T1,[EXP -1]		;IS IT -1, FOR "NOW"?
	  JRST	UDTDA1
	MOVX	T1,%CNDTM		;GET THE CURRENT UDT
	GETTAB	T1,			;...
	  HALT 				;DATE/TIME UNAVAILABLE - SNH
	MOVE	P3,T2			;MOVE THE DESTINATION INTO P3
	HRLI	P3,(POINT 7,0)		;AND MAKE IT A BYTE POINTER

UDTDA1:	PUSHJ	P,.CNTDT		;TAKE IT APART
	MOVE	P2,T2			;SAVE A RETURNED VALUE
	PUSH	P,T1			;SAVE TIME
	JUMPL	P1,UDTDA2		;IF FLAG IS UP, GIVE TIME ONLY
	MOVE	T1,T2			;POSITION DATE
	IDIVI	T1,^D31			;GET DAYS
	MOVE	T4,T1			;SAVE REST
	MOVEI	P1,1(T2)		;GET DAYS AS 1-31
	CAIGE	P1,^D10			;IF ONE DIGIT,
	PUSHJ	P,PUTSP			;FILL WITH A SPACE
	PUSHJ	P,PUTD			;PRINT DECIMAL NUMBER
	IDIVI	T4,^D12			;GET MONTHS
	MOVEI	P1,[ASCIZ /-Jan/
		    ASCIZ /-Feb/
		    ASCIZ /-Mar/
		    ASCIZ /-Apr/
		    ASCIZ /-May/
		    ASCIZ /-Jun/
		    ASCIZ /-Jul/
		    ASCIZ /-Aug/
		    ASCIZ /-Sep/
		    ASCIZ /-Oct/
		    ASCIZ /-Nov/
		    ASCIZ /-Dec/](P1)	;GET ASCII
	PUSHJ	P,PUTT			;TYPE THE ASCIZ STRING
	MOVEI	P1,^D64(T4)		;GET YEAR SINCE 1900
	IDIVI	P1,^D100		;GET JUST YEARS IN CENTURY
	MOVN	P1,P2			;NEGATE TO GET - SIGN
	PUSHJ	P,PUTD			;TYPE IT OUT
	PUSHJ	P,PUTSP			;NOW SPACE OVER ONE
UDTDA2:	POP	P,P1			;GET TIME BACK
	IDIV	P1,[DEC 3600000]	;GET HOURS
	MOVE	T4,P2			;SAVE REST
	CAIGE	P1,^D10			;IF ONLY ONE DIGIT,
	PUSHJ	P,PUTSP			;SPACE OVER
	PUSHJ	P,PUTD			;PUT DECIMAL NUMBER OUT
	PUSHJ	P,PUTCL			;NOW A COLON TO DIVIDE HOURS FROM MINUTES
	MOVE	P1,T4			;RESTORE REST
	IDIV	P1,[DEC 60000]		;GET MINUTES
	MOVE	T4,P2			;SAVE REST
	CAIGE	P1,^D10			;IF NOT TWO DIGITS,
	PUSHJ	P,PUT0			;GIVE A ZERO FILL
	PUSHJ	P,PUTD			;PRINT DECIMAL MINUTES
	PUSHJ	P,PUTCL			;AND SEPARATING COLON
	MOVE	P1,T4			;RESTORE THE REST
	IDIV	P1,[DEC 1000]		;EXTRACT THE SECONDS
	CAIGE	P1,^D10			;IF ITS NOT TWO DIGITS,
	PUSHJ	P,PUT0			; ZERO FILL IT
;	PJRST	PUTD			;THEN PRINT IT, RETURN
	PUSHJ	P,PUTD			;THEN PRINT IT
	PJRST	PUTZ			;MAKE IT ASCIZ, RETURN

SUBTTL	.CNTDT -- GENERALIZED DATE/TIME SUBROUTINE

;.CNTDT -- SUBROUTINE TO CONVERT FROM INTERNAL DATE/TIME FORMAT
;CALL:	MOVE	T1,DATE/TIME
;	PUSHJ	P,.CNTDT
;	RETURN WITH T1=TIME IN MS., T2=DATE IN SYSTEM FORMAT ( < 0 IF ARG < 0 )
;BASED ON IDEAS BY JOHN BARNABY, DAVID ROSENBERG, PETER CONKLIN
;USES T1-4

	RADIX	10		;***** NOTE WELL *****

MONTAB:	EXP	0,31,59,90,120,151,181,212,243,273,304,334,365

.CNTDT:	PUSH	P,T1		;SAVE TIME FOR LATER
	JUMPL	T1,CNTDT6	;DEFEND AGAINST JUNK INPUT
	HLRZ	T1,T1		;GET DATE PORTION (DAYS SINCE 1858)
	ADDI	T1,<1857-1500>*365+<1857-1500>/4-<1857-1500>/100+<1857-1500>/400+31+28+31+30+31+30+31+31+30+31+17
				;T1=DAYS SINCE JAN 1, 1501
	IDIVI	T1,400*365+400/4-400/100+400/400
				;SPLIT INTO QUADRACENTUR
	LSH	T2,2		;CONVERT TO NUMBER OF QUARTER DAYS
	IDIVI	T2,<100*365+100/4-100/100>*4+400/400
				;SPLIT INTO CENTURY
	IORI	T3,3		;DISCARD FRACTIONS OF DAY
	IDIVI	T3,4*365+1	;SEPARATE INTO YEARS
	LSH	T4,-2		;T4=NO DAYS THIS YEAR
	LSH	T1,2		;T1=4*NO QUADRACENTURIES
	ADD	T1,T2		;T1=NO CENTURIES
	IMULI	T1,100		;T1=100*NO CENTURIES
	ADDI	T1,1501(T3)	;T1 HAS YEAR, T4 HAS DAY IN YEAR

	MOVE	T2,T1		;COPY YEAR TO SEE IF LEAP YEAR
	TRNE	T2,3		;IS THE YEAR A MULT OF 4?
	JRST	CNTDT0		;NO--JUST INDICATE NOT A LEAP YEAR
	IDIVI	T2,100		;SEE IF YEAR IS MULT OF 100
	SKIPN	T3		;IF NOT, THEN LEAP
	TRNN	T2,3		;IS YEAR MULT OF 400?
	TDZA	T3,T3		;YES--LEAP YEAR AFTER ALL
	;UNDER RADIX 10 **** NOTE WELL ****

CNTDT0:	MOVEI	T3,1		;SET LEAP YEAR FLAG
				;T3 IS 0 IF LEAP YEAR
CNTDT1:	SUBI	T1,1964		;SET TO SYSTEM ORIGIN
	IMULI	T1,31*12	;CHANGE TO SYSTEM PSEUDO DAYS
	JUMPN	T3,CNTDT2	;IF NOT LEAP YEAR, PROCEED
	CAIGE	T4,31+29	;LEAP YEAR--SEE IF BEYOND FEB 29
	JRST	CNTDT5		;NO--JUST INCLUDE IN ANSWER
	SOS	T4		;YES--BACK OFF ONE DAY
CNTDT2:	MOVSI	T2,-11		;LOOP FOR 11 MONTHS

CNTDT3:	CAMGE	T4,MONTAB+1(T2)	;SEE IF BEYOND THIS MONTH
	JRST	CNTDT4		;YES--GO FINISH UP
	ADDI	T1,31		;NO--COUNT SYSTEM MONTH
	AOBJN	T2,CNTDT3	;LOOP THROUGH NOVEMBER

CNTDT4:	SUB	T4,MONTAB(T2)	;GET DAYS IN THIS MONTH
CNTDT5:	ADD	T1,T4		;INCLUDE IN FINAL RESULT

CNTDT6:	EXCH	T1,(P)		;SAVE ANSWER, GET TIME
	TLZ	T1,-1		;CLEAR DATE
	MUL	T1,[24*60*60*1000]	;CONVERT TO MILLI-SEC.
	ASHC	T1,17		;POSITION RESULT
	POP	P,T2		;RECOVER DATE
	POPJ	P,		;RETURN

	RADIX	8		;RETURN TO THE LAND OF THE NORM
; PUTD -- Put out a signed decimal number, number in P1

PUTD:: 	MOVE	P4,P1			;GET INTO PERMANENT PLACE
	JUMPGE	P4,PUTD.1		;IS IT NEGATIVE?
	PUSHJ	P,PUTDSH		;YES, SO PRINT A MINUS SIGN
	MOVMS	P4			;AND CONVERT TO POSITIVE
PUTD.1:	IDIVI	P4,^D10			;PICK OFF A DIGIT
 	HRLM	P5,0(P)			;BET YOU'VE SEEN THIS BEFORE
	SKIPE	P4			;ANY DIGITS LEFT?
	PUSHJ	P,PUTD.1		;YES, GET NEXT ONE
 	HLRZ	T3,0(P)			;GET A DIGIT
	ADDI	T3,"0"			;CONVERT TO ASCII
	PJRST	PUT7			;PUT OUT DIGIT, LOOP OR RETURN FORM THERE
; PUTT -- Output an ASCIZ string, address of string is in P1

PUTT:  	HRRZ	P4,P1			;GET ADDRESS INTO IT
	HRLI	P4,(POINT 7,0)		;CONVERT IT TO A BYTE POINTER
PUTT1:	ILDB	T3,P4			;GET A BYTE
	JUMPE	T3,CPOPJ		;IF NULL, RETURN
	PUSHJ	P,PUT7			;PRINT THE CHARACTER
	JRST	PUTT1			;LOOP FOR NEXT ONE

PUTSP:	MOVEI	T3," "
	PJRST 	PUT7

PUTCL:	MOVEI	T3,":"
	PJRST 	PUT7

PUTDSH:	MOVEI	T3,"-"
	PJRST 	PUT7

PUTZ:	MOVEI	T3,0
	PJRST	PUT7

PUT0:	MOVEI	T3,"0"
;	PJRST 	P,PUT7

PUT7:	IDPB	T3,P3
	POPJ	P,

; T1=PPN, T2=STRUCTURE IN SIXBIT, RETURNS T1-T3: IN, OUT, AND USED QUOTAS
; RETURNS+1 FOR NO UFD
; RETURNS+2 IF SUCCESSFUL
; *NOTE* THIS (AS EVERYTHING ELSE) SHOULD BE CHANGED TO USE FILOP.S
; *NOTE* ALSO THAT 377777,777777 EQUALS INFINITY


	QCHN=16

QUOTAS::MOVEM	T1,LKPBLK+.RBNAM	;PUT THE PPN IN THE FILENAME FIELD
	MOVEM	T1,FLPBLK+.FOPPN	;AND IN BAHALF OF THAT USER
	MOVE	T1,[%LDMFD]		;GET THE MASTER FILE DIRECTORY
	GETTAB	T1,			; ...
	  MOVE	T1,[1,,1]		;THIS WILL NEVER HAPPEN, BUT IF IT DOES
	MOVEM	T1,LKPBLK+.RBPPN	;STORE IT IN PPN FIELD
	HRLZI	T1,'UFD'		;WE ARE LOOKING UP THE UFD
	MOVEM	T1,LKPBLK+.RBEXT	;STORE EXTENSION IN FOR THE LOOKUP
	MOVEI	T1,.RBUSD		;STORE THE LENGTH
	MOVEM	T1,LKPBLK		;FOR THE LOOKUP
	MOVSI	T1,(UU.PHS)		;PHYSICAL DEVICE
	DMOVEM	T1,FLPBLK+.FOIOS	;SET UP THE FILOP BLOCK
	SETZM	FLPBLK+.FOBRH		;NO BUFFERS
	SETZM	FLPBLK+.FONBF		;I SAID NO BUFFERS
	SETZM	FLPBLK+.FOPAT		;NO RETURNED PATH
	MOVEI	T1,LKPBLK
	MOVEM	T1,FLPBLK+.FOLEB	;POINT TO LOOKUP BLOCK
	MOVE	T1,[FO.PRV!XWD QCHN,.FORED]
	MOVEM	T1,FLPBLK+.FOFNC	;JUST WANT TO FIND THE FILE
	MOVE	T1,[.FOPPN+1,,FLPBLK]
	FILOP.	T1,		;DO THE LOOKUP
	  POPJ	P,		;CAN'T
	MOVE	T1,[QCHN,,.FOREL]	;NOW GET RID OF THE CHANNEL
	MOVEM	T1,FLPBLK+.FOFNC
	MOVE	T1,[1,,FLPBLK]		;BY DOING A RELEAS
	FILOP.	T1,
	  JFCL
	MOVE	T1,LKPBLK+.RBQTF	;T1=LOGGED IN QUOTA
	MOVE	T2,LKPBLK+.RBQTO	;T2=LOGGED OUT QUOTA
	MOVE	T3,LKPBLK+.RBUSD	;T3=QUOTA USED
	JRST 	CPOPJ1			;SMILEY-FACED RETURN


;MISC ROUTINES
repeat 0,<
.SAVE1:	EXCH	P1,(P)		;SAVE P1, GET CALLER PC
	MOVEM	P1,1(P)		;SAVE CALLER PC ONE BEYOND END
	MOVE	P1,(P)		;RESTORE P1
	PUSHJ	P,@1(P)		;GO BACK TO CALLER, OVERWRITE CALLER PC WITH .+1
	  JRST	RES1
	AOS	-1(P)
	JRST	RES1

.SAVE2:	EXCH	P1,(P)		;SAVE P1, GET CALLER PC
	PUSH	P,P2
	MOVEM	P1,1(P)		;SAVE CALLER PC ONE BEYOND END
	MOVE	P1,-1(P)	;RESTORE P1
	PUSHJ	P,@1(P)		;GO BACK TO CALLER, OVERWRITE CALLER PC WITH .+1
	  JRST	RES2
	AOS	-2(P)
	JRST	RES2

.SAVE3:	EXCH	P1,(P)		;SAVE P1, GET CALLER PC
	PUSH	P,P2
	PUSH	P,P3
	MOVEM	P1,1(P)		;SAVE CALLER PC ONE BEYOND END
	MOVE	P1,-2(P)	;RESTORE P1
	PUSHJ	P,@1(P)		;GO BACK TO CALLER, OVERWRITE CALLER PC WITH .+1
	  JRST	RES3
	AOS	-3(P)
;	JRST	RES3

RES3:	POP	P,P3
RES2:	POP	P,P2
RES1:	POP	P,P1
	POPJ	P,

.SAV2T:	EXCH	T1,(P)		;SAVE T1, GET CALLER PC
	PUSH	P,T2
	MOVEM	T1,1(P)		;SAVE CALLER PC ONE BEYOND END
	MOVE	T1,-1(P)	;RESTORE T1
	PUSHJ	P,@1(P)		;GO BACK TO CALLER, OVERWRITE CALLER PC WITH .+1
	  SKIPA
	AOS	-2(P)
	POP	P,T2
	POP	P,T1
	POPJ	P,

>;end repeat 0

;BLDQUE	- returns the next .ENV file in UPS:
;	MOVE	T1,addr of one zeroed page (FIRST CALL ONLY)
;	PUSHJ	P,BLDQUE
;	  return here if no more .ENV files.  The zeroed page may be returned.
;	return here with next filename in T2
;
; uses T1-T3

	BUF=14			;ACS FOR THE BUFFER HEADER BLOCK
	LKP=15			;AND THE LOOKUP BLOCK
	FLP=16			;THE FILOP BLOCK

	UPS=15			;CHANNEL FOR READING UPS:.UFD

BLDQUE::EXCH	BUF,BLDSAV	;SAVE/RESTORE ACS
	EXCH	LKP,BLDSAV+1	; ...
	EXCH	FLP,BLDSAV+2	; ...
	SKIPE	BLDING		;HAVE WE INITED THE FILE?
	  JRST	BLDMOR		;YES, SKIP THIS STUFF
	MOVE	BUF,T1		;BUFFER HEADER
	ADDI	T1,3		;WHICH IS 3 WORDS LONG

	MOVE	LKP,T1		;LOOKUP BLOCK
	MOVE	T2,[XWD	5,35]	;FILE NAME
	MOVEM	T2,(T1)		;TO LOOKUP BLOCK
	AOS	T1		;POINT TO EXTENSION FIELD
	HRLZI	T2,'UFD'	;EXTENSION
	MOVEM	T2,(T1)		;INTO LOOKUP BLOCK
	ADDI	T1,3		;POINT PAST LOOKUP BLOCK

	MOVE	FLP,T1		;FILOP BLOCK
	MOVX	T2,<FO.PRV!<UPS>B17!.FORED>	;(.FOFNC) FUNCION READ
	MOVEM	T2,.FOFNC(FLP)
	MOVEI	T2,.IOIMG	;(.FOIOS) IMAGE MODE
	MOVEM	T2,.FOIOS(FLP)
	HRLZI	T2,'MFD'	;(.FODEV) DEVICE
	MOVEM	T2,.FODEV(FLP)
	MOVE	T2,BUF		;(.FOBRH) BUFFER HEADERS
	MOVEM	T2,.FOBRH(FLP)
	MOVEI	T2,1		;(.FONBF) BUFFERS
	MOVEM	T2,.FONBF(FLP)
	MOVE	T2,LKP		;(.FOLEB) LOOKUP BLOCK
	MOVEM	T2,.FOLEB(FLP)
	SETZ	T2,		;(.FOPAT) PATH BLOCK
	MOVEM	T2,.FOPAT(FLP)
	MOVE	T2,[5,,35]	;(.FOPPN) LOGGED IN AS UPS
	MOVEM	T2,.FOPPN(FLP)
	ADDI	T1,.FOPPN+1	;INCREMENT POINTER TO WORK SPACE
	EXCH	T1,.JBFF	;FUDGE .JBFF FOR OUR BUFFER
	MOVE	T2,FLP		;POINT TO THE FILOP BLOCK
	HRLI	T2,.FOPPN+1	;AND PLUG IN ITS LENGTH
	FILOP.	T2,		;OPEN FOR READ UPS:.UFD
	 HALT			;NO UFD FOR QUEUED MAIL!
	EXCH	T1,.JBFF	;FIX .JBFF
	SETOM	BLDING		;REBUILD IN PROGRESS, LETS REMEMBER THAT

BLDMOR:	HRLZI	T3,'ENV'	;SAVE EXTENSION FOR COMPARISONS
BLD.0:	PUSHJ	P,GETWRD	;GET A WORD FROM THE FILE
	 JRST	BLD.EN		;END OF FILE, SO CLOSE IT UP
	JUMPE	T1,[PUSHJ P,GETWRD	;IF NULL FILENAME READ EXTN
		     JRST BLD.EN	;(EOF), STOP
		    JRST BLD.0]	;TRY FOR A REAL FILE ENTRY
	MOVE	T2,T1		;GET THE NODE NAME SAFE AND SOUND

BLD.2:	PUSHJ	P,GETWRD	;GET THE EXT
	 JRST	BLD.EN		;THE END OF THE FILE
	HLLZS	T1		;GET THE EXTENSION
	CAME	T1,T3		;IS THIS AN ENV FILE?
	 JRST	BLD.0		;NOPE, LETS LOOK AT THE NEXT ONE
	AOS	(P)		;YEP, INDICATE GOOD RETURN (WITH FILNAME IN T2)
	JRST	BLDEND		;FINISH UP AND RETURN

BLD.EN:	CLOSE	UPS,		;CLOSE THE FILE
	RELEASE	UPS,		;AND RELEASE THE CHANNEL
	SETZM	BLDING		;ZERO FLAG SO WE START AT TOP
BLDEND:	EXCH	BUF,BLDSAV	;SAVE/RESTORE ACS
	EXCH	LKP,BLDSAV+1	; ...
	EXCH	FLP,BLDSAV+2	; ...
	POPJ	P,		;RETURN TO CALLER

	SUBTTL	GETWRD - Get a word from the file

GETWRD:	SOSGE	.BFCTR(BUF)	;ANY MORE LEFT?
	 JRST	CPYBIN		;INPUT A BYTE THEN

	ILDB	T1,.BFPTR(BUF)	;GET THE WORD IN T1
	JRST	CPOPJ1		;AND SKIP RETURN

CPYBIN:	IN	UPS,		;DO THE INPUT
	 JRST	GETWRD		;AND GET THE NEXT WORD
	POPJ	P,		;JUST RETURN

; CREATE OR DELETE UFDS
; CALL:	MOVEI	T1, USER PROFILE ADDRESS
;	PUSHJ	P,UFDCRE/UFDDEL
;	  <NON-SKIP>
;	<SKIP>
;
; NON-SKIP:	FAILED, ERROR MESSAGE ISSUED
; SKIP:		SUCCEEDED
;
; *** NOTE ***
; THIS ROUTINE REQUIRES AN EXTERNAL SUBROUTINE CALLED MXUFDE (MX UFD
; ERROR HANDLER).  IT WILL BE CALLED ON CATASTROPHIC ERRORS WITH T1
; CONTAINING A RIGHT-JUSTIFIED SIXBIT PREFIX AND T2 CONTAINING THE
; ADDRESS OF AN ASCIZ STRING.  RETURN IF VIA A POPJ.  NO ACS NEED BE
; PRESERVED.

UFDCRE::SKIPA	T2,[.UFMNT]	;MOUNT ENTRY POINT
UFDDEL::MOVEI	T2,.UFDMO	;DISMOUNT ENTRY POINT
	SETZM	ERRFLG		;CLEAR THE ERROR FLAG
	MOVEM	T1,PROFIL	;SAVE PROFILE ADDRESS
	PUSHJ	P,UFDINI	;INIT LOOP

UFDCOM:	MOVE	T1,[UFDBLK,,UFDBLK+1] ;SETUP BLT
	SETZM	UFDBLK		;CLEAR FIRST
	BLT	T1,UFDBLK+.UFSIZ-1 ;ZERO THEM ALL
	MOVE	T1,FUNCT	;GET FUNCTION CODE
	DPB	T1,[POINTR UFDBLK+.UFFLG,UF.FNC] ;STORE
	MOVE	T1,USRPPN	;GET TARGET PPN
	MOVEM	T1,UFDBLK+.UFPPN ;SAVE
	SETOM	UFDBLK+.UFJOB	;MY JOB
	SETOM	UFDBLK+.UFPRO	;DEFAULT (OR DON'T TOUCH) PROTECTION
	MOVX	T1,<UF.NRD!UF.IBP> ;IN BEHALF OF ANOTHER PPN (DON'T RECOMPUTE)
	IORM	T1,UFDBLK+.UFFLG
	MOVE	T1,AUXPTR	;GET AOBJN POINTER TO AUXACC DATA
	SKIPN	T2,.AUSTR(T1)	;GET A STRUCTURE NAME
	JRST	[ADD	T1,[.AULEN-1,,.AULEN-1]	;ACCOUNT FOR MISSING .AUBIT
		 JRST	UFDCO1]	;FIND NEXT ENTRY
	MOVEM	T2,UFDBLK+.UFSTR
;.AULIN
	AOBJN	T1,.+2		;OK IF NEXT FIELD
	TDZA	T2,T2		;NO, VALUE IS ZERO
	MOVE	T2,(T1)		;FCFS QUOTA
	MOVEM	T2,UFDBLK+.UFQTF
;.AUOUT
	AOBJN	T1,.+2		;OK IF NEXT FIELD
	TDZA	T2,T2		;NO, VALUE IS ZERO
	MOVE	T2,(T1)	        ;LOGGED OUT QUOTA
	MOVEM	T2,UFDBLK+.UFQTO
;.AURES
	AOBJN	T1,.+2		;OK IF NEXT FIELD
	TDZA	T2,T2		;NO, VALUE IS ZERO
	MOVE	T2,(T1)		;RESERVED QUOTA
	MOVEM	T2,UFDBLK+.UFQTR
;.AUBIT
	AOBJN	T1,.+2		;OK IF NEXT FIELD
	TDZA	T2,T2		;NO, VALUE IS ZERO
	MOVE	T2,(T1)		;STATUS BITS
	MOVEM	T2,UFDBLK+.UFSTS
	MOVEM	T1,AUXPTR	;UPDATE POINTER
	MOVEI	T1,CPOPJ	;GET TYPER
	MOVEM	T1,UFDBLK+.UFTYO ;SAVE
	MOVEI	T1,UFDBLK	;POINT TO ARGS
	PUSHJ	P,.UFD##	;DO SOMETHING
	  JRST	[PUSHJ	P,UFDERR	;REPORT THE ERROR
		JRST 	UFDCO0]		;SKIP PAST SUCCESS INDICATOR
	MOVEI	T1,1		;SUCESS...
	MOVEM	T1,ERRFLG	;...AT LEAST ONE STRUCTURE MOUNTED
UFDCO0:	MOVE	T1,AUXPTR	;GET AOBJN POINTER TO AUXACC DATA
UFDCO1:	AOBJP	T1,UFDXIT	;RETURN IF DONE
	MOVEM	T1,AUXPTR	;ELSE UPDATE POINTER
	JRST	UFDCOM		;AND LOOP BACK
; INITIALIZE UFD MOUNT/DISMOUNT LOOP
; CALL:	MOVE	T2, FUNCTION CODE
UFDINI:	MOVEM	T2,FUNCT	;SAVE FUNCTION CODE
	MOVE	T1,PROFIL	;GET PROFILE ADDRESS
	MOVE	T2,.AEAUX(T1)	;POINT TO START OF AUXACC DATA
	ADDI	T2,(T1)		;INDEX INTO THE PROFILE
	MOVEM	T2,AUXPTR	;SAVE
	MOVE	T2,.AEPPN(T1)	;GET PPN
	MOVEM	T2,USRPPN	;SAVE
	POPJ	P,		;RETURN


; EXIT PROCESSING
UFDXIT:	SKIPE	ERRFLG		;WAS THERE AN ERROR?
CPOPJ1:	AOS	(P)		;NO
CPOPJ:	POPJ	P,		;RETURN


; ERROR PROCESSING
; CALL:	PUSHJ	P,UFDERR
;	<NON-SKIP>		;ALWAYS, TO CONTINUE PROCESSING
repeat 0,<
UFDERR:	MOVEI	T2,.UFDMO	;FUNCTION TO CHECK
	CAME	T2,FUNCT	;DISMOUNTING ALL STRUCTURES?
	PUSHJ	P,UFDINI	;NO, RESET POINTERS FOR DISMOUNT
	AOS	ERRFLG		;INDICATE AN ERROR OCCURED
	HRRZ	T1,UFDBLK+.UFPFX ;GET SIXBIT PREFIX
	MOVE	T2,UFDBLK+.UFTXT ;AND ASSOCIATED ERROR TEXT
	PJRST	MXUFDE##	;REPORT UFD ERROR AND RETURN
> ;End repeat zero

UFDERR:	HRRZ	T1,UFDBLK+.UFPFX ;GET SIXBIT PREFIX
	MOVE	T2,UFDBLK+.UFTXT ;AND ASSOCIATED ERROR TEXT
	PJRST	MXUFDE##	;REPORT UFD ERROR AND RETURN


	END