	.title	k11rms	rms i/o for KERMIT-11
	.ident	/3.56.0/
	.library	/LB:[1,1]RMSMAC.MLB/


;	Brian Nelson  30-Nov-83  09:53:49
;
;	Copyright (C) 1983   Change Software, Inc.
;
; Edited by:
; RBD01 - Bob Denny 03-Mar-84	See K11CMD for edit trails
;
;
;	*******************************************************
;	*  NOTES REGARDING DECnet (DAP) REMOTE FILE SUPPORT)  *
;	*******************************************************
;
; The code here contains some magic for DECnet (DAP) remote file
; access.  I have not been able to find documentation on the DAP
; support that is present in RMS-11 (V2).  My current understanding
; of this, through experimentation, is as follows:
;
;	1. $PARSE fails with RMS status ER$UIN when given a file
;	   specification containing a node name, but seems to
;	   merge the input string and defaults into the expanded
;	   string buffer anyway.  It also sets the file specification
;	   mask.  I have assumed that the ER$UIN error is encountered
;	   in $PARSE after the merging of the default and input
;	   filespec information, and reflects the "fact" that RMS-11
;	   (V2) DOES NOT SUPPORT WILDCARDING ON REMOTE FILE ACCESS.
;
;	2. Therefore, lookup() has been modified to return the
;	   expanded string if its second calling parameter (index)
;	   is zero (1st call) and there is either a node name or a
;	   quoted literal in the spec, no wildcards and the error
;	   is ER$UIN.
;
;	3. fparse() has been modified to accept if the error is ER$UIN,
;	   and if there are no wildcards and there is a node name present.
;	   The FB$FID bit is cleared, however, so that the original
;	   file spec string and the defaults will be used by $OPEN.
;
;	4. The "SY:" defaulting is not necessary, and in fact causes
;	   remote accesses to fail on VMS systems, where "SY:" has
;	   no conventional meaning.
;
;	5. The other routines which use $parse have been similarly
;	   modified to use the expanded string once only.
;
;	6. Finally, the NAMCVT routine in K11M41 was changed to handle
;	   quoted sections in strings and node names.  This was the
;	   hardest part of the DAP adaptation.
;
; I have to believe that $parse and friends act this way because remote
; wildcarding got "left out" at the last minute because of scheduling
; problems in the RMS group.  The code I have added here should permit
; remote wildcarding when it is turned on by the RMS folks.
;
; Bob Denny	03-Mar-84
;
;
;
; Please note that RSTS rms11 requires a real default device. I thus
; have to put my origional default for SY: back in for RSTS only. We
; will determine this at tkb time by defining a global called FU$DEF
; to be <> 0 in K11E80.MAC  and = 0 in K11M41.MAC.
;
;
; Brian Nelson  16-Mar-84  17:34:19
;
; BDN 17-Feb-87  08:57:48  Re-do the allocation of record buffers so
;			   can GBLDEF the size during TKB. This will
;			   allow the I/D space Kermit to handle much
;			   larger ascii records.


;	define macros and things we want for KERMIT-11

	.if ndf, k11inc
	.ift


	.if ndf, K11INC
	.ift
	.include	/IN:K11MAC.MAC/
	.endc

	.endc
	.iif ndf, k11inc, .error ; INCLUDE for IN:K11MAC.MAC failed


;	This is K11RMS.MAC,  the RMS11 version 2 i/o interface for
;	Kermit on RSTS version 8, RSX11M+ v2.1 and RSX11M v4.1. It
;	is,  without a doubt,  the worst part of Kermit due RMS11,
;	but it's strong points are  future uses and the RSX / RSTS
;	transportability.  An example of "future uses" is DECnet
;	remote file access (DAP) support now present.
;
;
;	open  ( %loc filename, %val channel_number ,%val type )
;	create( %loc filename, %val channel_number ,%val type )
;	getrec( %loc buffer  , %val channel_number ) { returns RSZ in R1}
;	putrec( %loc buffer  , %val record_size    ,%val channel_number )
;	close ( %val channel_number )
;	putc  ( %val char    , %val channel_number )
;	getc  ( %val channel_number )


	cr	=	15
	lf	=	12
	ff	=	14
	soh	=	1
;
; This isn't defined globally. (??)
;
	nb$nod	=	400	; Node in file or default string (FNB in NAM)

	.enabl	gbl

	.psect	$code	,ro,i,lcl,rel,con
	.psect	rmssup	,rw,d,lcl,rel,con


	.mcall	fabof$
	.mcall	rabof$
	.mcall	xabof$
	.mcall	ifaof$

	fabof$	RMS$L
	rabof$	RMS$L
	xabof$	RMS$L
	ifaof$	RMS$L


	.mcall	fab$b	,fab$e	,rab$b	,rab$e
	.mcall	xab$b	,xab$e
	.mcall	nam$b	,nam$e
	.mcall	$initif	,org$
	.mcall	pool$b	,pool$e	,p$bdb	,p$fab
	.mcall	p$rabx	,p$idx	,p$buf

	.mcall	$compar	,$fetch	,$store	,$rewin
	.mcall	$close	,$creat	,$erase	,$open
	.mcall	$connec	,$delet	,$discon,$find
	.mcall	$get	,$put	,$updat	,$flush
	.mcall	$read	,$write	,$off	,$set
	.mcall	$testbits


	org$	SEQ,<CRE,DEL,GET,PUT>

	.psect	rmssup	,rw,d,lcl,rel,con ; ORG$ macro needs .save/.restore


	.if ne	,0			; Decide whether or not to use
	.ift				; dynamic space allocation by
					; task extension or to use
rmsbuf:	pool$b				; static pools
	p$rab	6			; plenty of record streams
	p$bdb	6			; same goes for block buffers
	p$fab	4			; up to 3 fabs (needed for search)
	p$buf	3072.			; for 2 files and directory i/o
	pool$e				; end of static pool

	.iff				; use task extension for space
					; routine modifed from GSA example
	.mcall	gsa$			; from RMS v2.0 distribution.
	gsa$	gsa			; set our GSA address
	.globl	gsa			; it may be global

	.endc				; to decide on pool allocation

	.psect	rmssup	,rw,d,lcl,rel,con ; GSA$ macro needs .save/.restore



	.sbttl	rms file access blocks

	facc	=	fb$get ! fb$put

fab1:	fab$b
	f$alq	0			; initial allocation of 10 blocks
	f$fac	facc			; allowed i/o operations
	f$fna	nam1			; name of the file
	f$fns	0			; length of the filename
	f$fop	fb$sup			; supercede old versions
	f$lch	lun1			; channel number to use
	f$org	fb$seq			; seq
	f$rat	fb$cr			; implied carriage control
	f$rfm	fb$var			; variable length records
	f$xab	datxb1			; Date info
	fab$e
fab1en:

fab2:	fab$b
	f$alq	0			; initial allocation of 10 blocks
	f$fac	facc			; allowed i/o operations
	f$fna	nam2			; name of the file
	f$fns	0			; length of the filename
	f$fop	fb$sup			; supercede old versions
	f$lch	lun2			; channel number to use
	f$org	fb$seq			; seq
	f$rat	fb$cr			; implied carriage control
	f$rfm	fb$var			; variable length records
	f$xab	datxb2			; Date info
	fab$e
fab2en:


fab3:	fab$b
	f$alq	0			; initial allocation of 10 blocks
	f$fac	facc			; allowed i/o operations
	f$fna	nam3			; name of the file
	f$fns	0			; length of the filename
	f$fop	fb$sup			; supercede old versions
	f$lch	lun3			; channel number to use
	f$org	fb$seq			; seq
	f$rat	fb$cr			; implied carriage control
	f$rfm	fb$var			; variable length records
	f$xab	datxb3			; Date info
	fab$e
fab3en:


fab4:	fab$b
	f$alq	0			; initial allocation of 10 blocks
	f$fac	facc			; allowed i/o operations
	f$fna	nam4			; name of the file
	f$fns	0			; length of the filename
	f$fop	fb$sup			; supercede old versions
	f$lch	lun4			; channel number to use
	f$org	fb$seq			; seq
	f$rat	fb$cr			; implied carriage control
	f$rfm	fb$var			; variable length records
	f$xab	datxb4			; Date info
	fab$e

	GLOBAL	<MAXSIZ>


	.psect	rmssup	,rw,d,lcl,rel,con

sydisk::.ascii	/SY:/
sylen	==	. - sydisk
	.even
sydska	==	sydisk
sydskl	==	sylen

;								;RBD01--
;	pointers to buffer and fabs
;
;	While none of this is really needed since all this info is
;	available in  the FAB and RAB,  I find it cleaner to do it
;	this way and thus avoid having to look at the  RMS control
;	structures.

fablst::.word	0	,fab1	,fab2	,fab3	,fab4
namlst::.word	0	,nam1	,nam2	,nam3	,nam4
namlen::.word	0	,0	,0	,0	,0
rablst::.word	0	,rab1	,rab2	,rab3	,rab4
buflst:	.word	ttbuf	,buf1	,buf2	,buf3	,buf4
bufdef:	.word	ttbuf	,buf1	,buf2	,buf3	,buf4
bufsiz:	.word	TTBSIZ	,MAXSIZ	,MAXSIZ	,MAXSIZ	,MAXSIZ
bigbuf:	.word	bufx	,bufx	,bufx	,bufx	,bufx
filtyp:	.word	TERMINAL,TEXT	,TEXT	,TEXT	,TEXT
bufp:	.word	0	,0	,0	,0	,0
bufs:	.word	0	,0	,0	,0	,0
mode:	.word	1	,0	,0	,0	,0
blknum:	.word	0	,0	,0	,0	,0
itsopen:.word	0	,0	,0	,0	,0

	FILSIZ	==	110.
	BINLSIZ	==	30*4

defdir::.blkb	FILSIZ+2		; default directory for send and rec
srcnam::.blkb	FILSIZ+2		; original send filespec
filnam::.blkb	FILSIZ+2		; output from directory lookup routine
asname::.blkb	FILSIZ+2		; for SEND file [as] file
$cmdbu::.blkb	120
$argbu::.blkb	120
bintyp::.word	10$
10$:	.rept	BINLSIZE
	.byte	0
	.endr
totp.r::.word	10$
10$:	.rept	34
	.word	0,0
	.endr
totp.s::.word	10$
10$:	.rept	34
	.word	0,0
	.endr

;	this sets the default for creating text files

df$rat::.word	fb$cr
df$rfm::.word	fb$var
en$siz::.word	0			; for RT11 compatibilty

namln1	=	namlen+2
namln2	=	namlen+4
namln3	=	namlen+6
namln4	=	namlen+10

nam1:	.rept	100
	.byte	0
	.endr

nam2:	.rept	100
	.byte	0
	.endr

nam3:	.rept	100
	.byte	0
	.endr

nam4:	.rept	100
	.byte	0
	.endr
	.even


packet::.blkb	MAXLNG+100		; /51/ Moved.
	.even

top:	.LIMIT

	TTBSIZ	=	40
ttbuf:	.blkb	TTBSIZ+2

buf1:	.iif df, MAXSIZ, .blkb MAXSIZ+2	; /56/ Dynamic or static setup?
buf2:	.iif df, MAXSIZ, .blkb MAXSIZ+2	; /56/ ...
buf3:	.iif df, MAXSIZ, .blkb MAXSIZ+2	; /56/ ....
buf4:	.iif df, MAXSIZ, .blkb MAXSIZ+2	; /56/ .....

bufx:	.blkb	1002			; one large buffer to share


lun1	=	1
lun2	=	2
lun3	=	3
lun4	=	4
maxlun	=	lun4



	.sbttl	rms record access blocks

rab1:	rab$b				; define record access block
	r$fab	fab1			; associate a fab with this rab
	r$rac	rb$seq			; access by keys
	r$rbf	buf1			; where to return the data
	r$ubf	buf1			; where to return the data
	rab$e				; end of record access block

rab2:	rab$b				; define record access block
	r$fab	fab2			; associate a fab with this rab
	r$rac	rb$seq			; access by keys
	r$rbf	buf2			; where to return the data
	r$ubf	buf2			; where to return the data
	rab$e				; end of record access block

rab3:	rab$b				; define record access block
	r$fab	fab3			; associate a fab with this rab
	r$rac	rb$seq			; access by keys
	r$rbf	buf3			; where to return the data
	r$ubf	buf3			; where to return the data
	rab$e				; end of record access block

rab4:	rab$b				; define record access block
	r$fab	fab4			; associate a fab with this rab
	r$rac	rb$seq			; access by keys
	r$rbf	buf4			; where to return the data
	r$ubf	buf4			; where to return the data
	rab$e				; end of record access block



proxab:	xab$b	XB$PRO			; file protection xab
	x$nxt	0			; no more links
	x$pro	60.			; normal protection of <60>
	xab$e				; end of file protection xab

datxb1:	xab$b	XB$DAT
	x$nxt	0
	xab$e
datxb2:	xab$b	XB$DAT
	x$nxt	0
	xab$e
datxb3:	xab$b	XB$DAT
	x$nxt	0
	xab$e
datxb4:	xab$b	XB$DAT
	x$nxt	0
	xab$e

	.psect	$code


	.sbttl	Set up SST table to catch RMSRES missing

	.mcall	SVTK$S,EXST$S,EXTK$S	; This code added /53/
	.mcall	GTSK$S

;	Dynamic record buffer allocation and dynamic recall buffer
;	allocation added /56/


	.save				; Save current PSECT
	.psect	RMSSUP	,D		; Switch to a data psect
	.even				; Insure this
tbl:	.word	0,0,norms		; Missing RMS gives a BPT trap
nolib:	.byte	CR,LF
	.ascii	/Probable cause: Either RMSRES or an RMS satellite/<CR><LF>
	.asciz	/resident library is not installed on this system./<CR><LF>
	.even
	.restore			; Pop old psect
	.enabl	lsb


Rmsini::mov	#MAXSIZ	,r3		; Allocate record buffers
	mov	r3	,O$MRS+fab1	; Since we are allocating
	mov	r3	,O$MRS+fab2	; the RMS record buffers at
	mov	r3	,O$MRS+fab3	; run time we will can't
	mov	r3	,O$MRS+fab4	; fill these fields in with
	mov	r3	,O$USZ+rab1	; ...MAC
	mov	r3	,O$USZ+rab2	; .... and so on
	mov	r3	,O$USZ+rab3	; ....
	mov	r3	,O$USZ+rab4	; ....
					;
	.If df	,MAXSIZ			; Dynamic or static today?
	.Ift				; Static
					;
	mov	#buf1	,r2		; So get the preallocated buffers
	mov	top+2	,r4		;
	.Iff				; Dynamic allocation
					;
	ash	#-<6-2>	,r3		; We need 4 buffers, in 64 byte
	add	#2	,r3		; chuncks. Add a safety margin
	EXTK$S	r3			; Ask for the memory
	bcs	110$			; Oops, we will have to die.
	mov	top+2	,r2		; The higest virtual address+2
	add	#2	,r2		; filled in by TKB via .LIMIT
	bic	#1	,r2		; Insure even
					;
	.Endc				; .If DF, Maxsiz
					;
	mov	#4	,r0		; Number of fields to update
	clr	r3			; Offset into BUFDEF and BUFLST
10$:	mov	r2	,bufdef+2(r3)	; Insert a record buffer address
	mov	r2	,buflst+2(r3)	; Ditto for here also
	add	#2	,r3		; Next please
	add	#MAXSIZ+2,r2		; Point to the next buffer
	sob	r0	,10$		; And go do another
	.If ndf	,MAXSIZ			; Setup pointer for command line
	mov	r2	,r4		; recall buffers if dynamic RMS
	.Endc				; buffer allocation was used
					; Now for command line recall
	mov	#LNCNT$	,r1		; buffers. The count is defined
	cmp	r1	,#LN$ALL	; via a GBLDEF=LNCNT$:n by TKB.
	bgt	120$			; Ensure enough vector space. No, die
	mov	#<LN$MAX+2>*LNCNT$,r3	; Total byte count for recall buffers
	ash	#-6	,r3		; In 64 byte chunks
	add	#<LN$MAX+2>/100,r3	; Fix for truncation
	EXTK$S	r3			; Ask for it
	bcs	130$			; No room, die (should never happen)
	mov	r1	,lastcnt	; Save the number of recall buffers
	mov	#lastli	,r2		; The pointer array
40$:	mov	r4	,(r2)+		; Insert the buffer address
	clrb	@r4			; Insure the buffer is zapped
	add	#LN$MAX+2,r4		; Get to the next one
	sob	r1	,40$		; And loop
					;
					; Finally, our original purpose.
	SVTK$S	#tbl,#3			; Only want TBIT traps
	return				; Exit


110$:	Message	<Failure to allocate record buffers>,CR
	br	200$
120$:	Message	<LN$ALL is less than LNCNT$>,CR
	br	200$
130$:	Message	<Failure to allocate command recall buffers>,CR

200$:	EXST$S	#EX$SEV			; Die...

	.dsabl	lsb



Norms:	MESSAGE	<Breakpoint trap, >	; A message
	mov	(sp)	,r1		; Dump PC and PS
	MESSAGE	< PC: >			; A header
	OCTOUT	R1			; ...
	mov	2(sp)	,r1		; PS
	MESSAGE	<  PSW: >		; ...
	OCTOUT	r1			; ...
	cmp	(sp)	,#140000	; Perhaps RMSRES missing?
	blo	100$			; No
	PRINT	#nolib			; Dump the cause
100$:	EXST$S	#EX$SEV			; Die

	Global	<LNCNT$>




	.sbttl	create sequential file
	.psect	$code
	.even

;	F C R E A T E    and   FOPEN
;
;	fcreate( %loc filename; %val channel_number, %val type ,%val mb_count)
;	fopen  ( %loc filename; %val channel_number, %val type ,%val mb_count)
;
;	input:	@r5	filename address
;		2(r5)	channel number
;		4(r5)	val 'binary' or 'text' or 0
;		6(r5)	RMS multiblock count for the stream
;
;	output:	r0	rms error code
;
;	 Create a variable length sequential implied carriage control
;	disk file.  If 'type' is 'binary'  then use read/write access
;	to write  a fixed  512 byte image file. If  channel number is
;	zero (0),  then initialize  buffer single character  terminal
;	output.  It is always assumed that channel '0' implies writes
;	to the attached console terminal.

	.enabl	lsb
open::	calls	fopen	,<@r5,2(r5),4(r5),#0>
	return

create::calls	fcreate	,<@r5,2(r5),4(r5),#0>
	return

append::calls	fapnd	,<@r5,2(r5),4(r5),#0>
	return


fopen::	save	<r1,r2,r3>		; save registers
	call	drpprv			; insure no privs are up now	+MJG
	clr	-(sp)			; flag for open not create
	br	5$			; and try to do it


fapnd::	save	<r1,r2,r3>		; save registers		+SSH
	call	drpprv			; insure no privs		+SSH
	mov	#1,-(sp)		; flag for open / append	+SSH
	br	5$			; and try to do it		+SSH


fcreat::save	<r1,r2,r3>		; save registers
	call	drpprv			; insure no privs are up now	+MJG
tcreat:	mov	#-1	,-(sp)		; flag for create

5$:	$initif				; initialize rms i/o system if needed
	mov	2(r5)	,r0		; get channel number please
	bne	10$			; not channel zero, do it normally

	mov	sp	,itsopen+0	; flag it as having been initted
	mov	sp	,mode+0		; psuedo writing to the terminal
	clr	bufp+0			; initialize the terminal's buffer
	br	120$			; pointer and exit

10$:	asl	r0			; times 2
	mov	r0	,r2		; save it please
	mov	namlst(r2),r1		; get address of name block
	calls	fparse	,<@r5,r1>	; parse and fill in defaults
	tst	r0			; did the parse succeed ?
	bne	120$			; no, exit with RMS error in r0
	strlen	r1			; get the expanded filename length
	mov	r0	,namlen(r2)	; and save the length
	mov	r2	,r0		; get r0 back again please
	mov	fablst(r0),r1		; get the file access block
	mov	@sp	,r2		; pass create/open/append flag	   /SSH
	call	settyp			; setup the FAB now
	mov	r0	,r2		; save the channel number*2
	tst	@sp			; create or open or append	   /SSH
	bmi	30$			; if negative then create	   /SSH

	$open	r1			; try to open existing file	   /SSH
	tst	@sp			; opening for append ?		   +SSH
	beq	28$			; no, go setup for read		   +SSH
	mov	sp	,mode(r2)	; indicate open for writing	   +SSH
	clr	bufp(r2)		; clear single char i/o pointer    +SSH
	br	40$			; continue with status check	   +SSH
28$:					;				   +SSH
	mov	#-1	,bufp(r2)	; init for buffer needing a read
	clr	mode(r2)		; no writing please
	br	40$			; check RMS status out now

30$:	$creat	r1			; try hard to create the file
	mov	sp	,mode(r2)	; open for writing
	clr	bufp(r2)		; clear single character i/o pointer

40$:	$fetch	r0,sts,r1		; get status back out please
	tst	r0			; if status > 0 then status = 0
	bmi	130$			; error if less than zero	   /SSH
	mov	2(r5)	,r0		; connect access up now
	asl	r0			; flag also that we are open
	mov	sp	,itsopen(r0)	; simple
	asr	r0			; restore r0 now
	mov	6(r5)	,r1		; and the multiblock count also
	mov	(sp)	,r2		; and the create/open/append opt   +SSH
	call	rmscon			; connect record stream up
	tst	r0			; if error > 0 then error = 0
	bmi	120$			; yep
	clr	r0			; error = 0

120$:	tst	(sp)+			; pop open/create flag
125$:	unsave	<r3,r2,r1>		; pop registers we saved
	return				; and exit

130$:	tst	(sp)+			; if error on open for append	   +SSH
	ble	125$			; no, return with error		   +SSH
	br	tcreat			; yes, try creating the file	   +SSH

	global	<drpprv>		;				+MJG

	.dsabl	lsb

	.sbttl	setup things for open/create in the FAB


;	S E T T Y P
;
;	input:	r0	channel number times 2
;		r2	<> 0 implies create
;		r5	--> open/create parameter list
;
	fbrw	=	fb$rea ! fb$wri

settyp::mov	fablst(r0),r1
	clr	blknum(r0)		; in case of read/write mode
	mov	#MAXSIZ	,bufsiz(r0)	; default for the buffer size
	mov	#text	,filtyp(r0)	; assume ascii text files for now
	mov	bufdef(r0),buflst(r0)	; set a default record buffer also
	clr	bufs(r0)		; clear single character i/o recsiz
	$store	#proxab,XAB,r1		; /59/ Get the protection out.
	$store	namlen(r0),FNS,r1
	$store	#fb$seq,ORG,r1		; insure sequential by default
	$store	df$rat ,RAT,r1		; implied carriage control
	$store	df$rfm ,RFM,r1		; and also variable length records
	$store	#fb$get,FAC,r1		; insure readonly please
	tst	fu$def			; do we require a default device
	beq	1$			; no
	$store	#sydisk,DNA,r1		; yes, stuff the correct def dev in
	$store	#sylen ,DNS,r1		; and the length of it also please
1$:	tst	r2			; if creating or appending the file /SSH
	beq	10$			; no				    /SSH
	$store	#<fb$put>,FAC,r1 	; yes, get put access   	    /SSH
	mov	at$pr0	,proxab+O$PRO	; /59/ Protection explicity set?
	bne	10$			; /59/ Yes
	$store	#0,XAB,r1		; /59/ No, remove the protection XAB
10$:	cmp	4(r5)	,#binary	; is this a binary file ?
	bne	100$			; no, just exit

	mov	#1000	,bufsiz(r0)	; yes, fix it up for that
	mov	bigbuf(r0),buflst(r0)	; setup a large i/o buffer please
	mov	#binary	,filtyp(r0)	; please
	$store	#0	,RAT,r1		; no cr/lf implied please
	$store	#fb$fix	,RFM,r1		; fixed length also
	$store	#fb$rea	,FAC,r1		; assume read only please
	tst	r2			; readonly ?
	beq	30$			; yes
	$store	#fbrw	,FAC,r1		; read/write mode needed ?
30$:	save	<r2,r3>			; zero out the big buffer
	mov	buflst(r0),r2		; get the buffer address
	mov	#1000	,r3		; 1000 (8) bytes please
40$:	clrb	(r2)+			; simple
	sob	r3	,40$		; next please
	unsave	<r3,r2>			; pop registers we just used

100$:	$store	bufsiz(r0),MRS,r1	; stuff max recordsize in please
	return

	global	<fu$def>
	GLOBAL	<AT$PR0>		; /59/ Protection mask



	.sbttl	close a file


close::	save	<r1,r2,r3>		; save registers we may have
	mov	@r5	,r0		; get the lun
	asl	r0			; times 2
	tst	itsopen(r0)		; check for lun being open
	beq	90$			; no, skip all this then
	clr	itsopen(r0)		; not anymore please
	call	flush			; dump out any remaining buffer
	mov	@r5	,r0		; then disconnect the access stream
	beq	100$			; terminal

	asl	r0			; channel number times 2
	tst	mode(r0)		; writing to it today?
	beq	10$			; no
	calls	atrfin	,<@r5>		; yes, perhaps do attribute things
10$:	mov	@r5	,r0		; then disconnect the access stream
	call	rmsdis			; by doing a $disconnect
	mov	@r5	,r1		; get the FAB for the file open on
	asl	r1			; the passed channel
	mov	fablst(r1),r1		;
	$close	r1			; try hard to close the file
	$fetch	r0,sts,r1		; get status back out please
	tst	r0			; if status > 0 then status = 0
	blt	100$			; error if less than zero
90$:	clr	r0			; make > 0 status eq 0
100$:	unsave	<r3,r2,r1>
	return


rewind::mov	@r5	,r0
	beq	100$
	asl	r0
	mov	rablst(r0),r0
	$rewind	r0
100$:	clr	r0
	return



	.sbttl	try to determine if a file needs binary xfer mode

;	B I N F I L
;
;	input:	@r5	address of the filename
;		2(r5)	lun
;	output:	r0	< 0 then RMS error
;		r0	> 0 then the file is most likely binary


binfil::save	<r1,r2,r3,r4>		; save registers we may use
	clr	r4			; nothing is open as of yet
	calls	chkext	,<@r5>		; check file based on filetype
	tst	r0			; assume a binary file ?
	bne	100$			; yep
	mov	2(r5)	,r2		; get the lun
	asl	r2			; times 2
	mov	fablst(r2),r2		; get the fab address now
	$fetch	r3,XAB,r2		; save the xab link address
	call	getuic			; for RSTS, skip the protection XAB
	swab	r0			; if the user is not privledged
	cmpb	r0	,#1		; since RMS uses the UU.LOK directive
	bne	5$			; which may be patched to fail.
	$store	#proxab,XAB,r2		; and stuff our own into it
5$:	calls	open	,<@r5,2(r5),#binary>
	tst	r0			; did the open work
	bmi	90$			; no
	mov	sp	,r4		; flag that it's open

	call	getsys			; if this is RSTS then a protection
	cmpb	r0	,#sy$rsts	; bit of 100 being set indicates an
	bne	10$			; executable file
	mov	#proxab	,r1		; get the xab for the protection code
	$testbit #100,PRO,r1		; if set, then it's executable
	bne	40$			; assume it's binary

10$:	$testbit #<fb$rel!fb$idx>,ORG,r2; indexed or relative file ?
	bne	40$			; yes, it must be sent as a binary file
	$compare #fb$stm,RFM,r2		; stream ascii file ?
	beq	30$			; yes, assume not binary then
	$testbit #FB$FTN,RAT,r2		; /47/ Please not for Fortran files
	bne	30$			; /47/ Ok
	$testbit #fb$cr,RAT,r2		; implied carriage control ?
	bne	30$			; yes, assume not 8 bit then
	br	40$			; anything else is binary please
	

30$:	clr	-(sp)			; flag as most likely being ascii
	br	50$			; bye
40$:	mov	#1	,-(sp)		; flag as being binary and exit
50$:	tst	r4			; ever opened up ?
	beq	60$			; no
	calls	close	,<2(r5)>	; close up
60$:	mov	(sp)+	,r0
90$:	$store	r3,XAB,r2		; restore old xab links, if any

100$:	unsave	<r4,r3,r2,r1>		; bye
	return


	.sbttl	getatr	return attributes for a file already open

	.mcall	ifaof$			; access the ifab for the fab
	ifaof$	rms$l			; get the ifab symbols defined


getsiz::mov	@r5	,r1		; return error in r0, size in r1
	asl	r1			; lun times 2
	mov	fablst(r1),r1		; fab for this file
	mov	<o$alq+0>(r1),r1	; get the size please
	clr	r0			; no errors 
	return				; exit

getpro::mov	@r5	,r0		; size in r0
	asl	r0			; lun times 2
	mov	fablst(r0),r0		; fab for this file
	mov	O$XAB(r0),r0		; get the protection please
	mov	O$PRO(r0),r0		; ...
	return				; exit



;	Getcdt	Return time/date of creation, system (ie, RMS vs RT) dep.
;
;	Passed:	2(r5)	Channel number file is open on
;	Return:	R0	Zero if failure (internal error) else address of
;			64 byte Smithsonian date format


Getcdt::mov	@r5	,r0		; Channel
	beq	100$			; Oops
	asl	r0			; Word offsets
	mov	FABLST(r0),r0		; Get the fab
	beq	100$			; Impossible
	mov	O$XAB(r0),r0		; XAB address
	beq	100$			; Nothing
	add	#O$CDT	,r0		; Point to 4word creation dat/tim
100$:	return				; Exit

Putcdt::mov	@r5	,r0		; Channel
	beq	100$			; Oops
	asl	r0			; Word offsets
	mov	FABLST(r0),r0		; Get the fab
	beq	100$			; Impossible
	mov	O$XAB(r0),r0		; XAB address
	beq	100$			; Nothing
	add	#O$CDT	,r0		; Point to 4word creation dat/tim
	mov	2(r5)	,r1		; Data
	mov	(r1)+	,(r0)+		; Copy it
	mov	(r1)+	,(r0)+		; .Copy it
	mov	(r1)+	,(r0)+		; ..Copy it
	mov	(r1)+	,(r0)+		; ...Copy it
100$:	return				; Exit


getatr::save	<r1,r2>			; save these please
	mov	@r5	,r1		; the channel number please
	asl	r1			; times two please
	mov	fablst(r1),r1		; simple
	mov	o$ifi(r1),r1		; and now we are at the ifab
	mov	2(r5)	,r2		; where to copy the attributes to
	movb	f$ratt(r1),(r2)+	; stuff the input record attributes
	movb	f$forg(r1),(r2)+	; also stuff the input file org in
	mov	f$rsiz(r1),(r2)+	; and the input record size please
	mov	f$hvbn(r1),(r2)+	; and the input eof markers
	mov	f$lvbn(r1),(r2)+	; like hi and low virtual block
	mov	f$heof(r1),(r2)+	; and the high and low eof block
	mov	f$leof(r1),(r2)+	; numbers also
	mov	f$ffby(r1),(r2)+	; and, at last, the first free byte
	movb	f$hdsz(r1),(r2)+	; VFC header size next
	movb	f$bksz(r1),(r2)+	; and largest bucket size
	mov	f$mrs(r1) ,(r2)+	; the maximum record size
	mov	f$deq(r1) ,(r2)+	; and the default extenstion size
	mov	f$rtde(r1),(r2)+	; and the run time extentsion size
100$:	unsave	<r2,r1>			; all done
	clr	r0			; say it worked ok
	return



putatr::save	<r1,r2>			; save these please
	mov	@r5	,r1		; the channel number please
	asl	r1			; times two please
	mov	fablst(r1),r1		; simple
	mov	o$ifi(r1),r1		; and now we are at the ifab
	mov	2(r5)	,r2		; where to get the attributes from
	movb	(r2)+	,f$ratt(r1)	; stuff the input record attributes
	movb	(r2)+	,f$forg(r1)	; also stuff the input file org in
	mov	(r2)+	,f$rsiz(r1)	; and the input record size please
	mov	(r2)+	,f$hvbn(r1)	; and the input eof markers
	mov	(r2)+	,f$lvbn(r1)	; like hi and low virtual block
	mov	(r2)+	,f$heof(r1)	; and the high and low eof block
	mov	(r2)+	,f$leof(r1)	; numbers also
	mov	(r2)+	,f$ffby(r1)	; and, at last, the first free byte
	movb	(r2)+	,f$hdsz(r1)	; VFC header size next
	movb	(r2)+	,f$bksz(r1)	; and largest bucket size
	mov	(r2)+	,f$mrs(r1) 	; the maximum record size
	mov	(r2)+	,f$deq(r1) 	; and the default extenstion size
	mov	(r2)+	,f$rtde(r1)	; and the run time extentsion size
100$:	unsave	<r2,r1>			; all done
	clr	r0			; say it worked ok
	return





	.sbttl	connect record access block to file access block


;	C O N N E C T
;
;	connect( %val channel_number )
;
;	input:	r0	channel number
;		r1	multiblock count
;		r2	create/open/append option flag			+SSH
;	output:	r0	rms sts
;
;	Connect a record access block to a file access block.
;	Called only from OPEN and CREATE


rmscon:	mov	r1	,-(sp)		; the block count size
	mov	r0	,r1		; get address of record access block
	asl	r1			; channel number times 2
	mov	rablst(r1),r1		; address of a rab to use
	$store	(sp)+,MBC,r1		; the block buffer count
	$store	#0,ROP,r1		; assume no processing options	   +SSH
	tst	r2			; if appending to existing file	   +SSH
	ble	7$			; no, leave options alone	   +SSH
	$store	#rb$eof,ROP,r1		; yes, set position to EOF option  +SSH
7$:					;				   +SSH
	$conne	r1			; try hard to connect access up
	$fetch	r0,sts,r1		; get status back out please
	tst	r0			; if status > 0 then status = 0
	blt	10$			; error if less than zero
	clr	r0			; make > 0 status eq 0
10$:	return




	.sbttl	disconnect record access block from file access block


;	R M S D I S
;
;	input:	r0	channel number
;		r0	error sts
;

rmsdis:	mov	r0	,r1
	asl	r1
	mov	rablst(r1),r1
	$discon	r1			; disconnect access stream from file
	$fetch	r0,sts,r1		; get status back out please
	tst	r0			; if status > 0 then status = 0
	blt	10$			; error if less than zero
	clr	r0			; make > 0 status eq 0
10$:	return



	.sbttl	read a record from a sequential file


;	G E T R E C
;
;	getrec( %loc buffer, %val channel_number )
;
;	input:	@r5	address of user buffer, at least 80 bytes
;		2(r5)	channel number
;
;	output:	r0	rms sts
;		r1	record size
;
;	Read the next record from a disk file. Assumes that the
;	user  has supplied a buffer of 80 characters to  return
;	the record to.


getrec::mov	2(r5)	,r0		; get the channel number
	asl	r0			; times 2 to index into table
	mov	rablst(r0),r1		; get the record access buffer
	$store	#0  ,RSZ,r1
	$store	@r5 ,UBF,r1		; stuff a record buffer in
	$store	bufsiz(r0),USZ,r1	; and a maximum record size
	cmp	filtyp(r0),#binary	; a binary file today ?
	bne	10$			; no, use normal get$
	clr	o$bkt+0(r1)		; use sequential mode please
	clr	o$bkt+2(r1)		; both words are to have zero
	$read	r1			; get next virtual block please
	br	20$			; get error code out now
10$:	$get	r1			; read a record now
20$:	$fetch	r0,STS,r1		; get the return STATUS field
	tst	r0			; did it work ?
	blt	100$			; no
	clr	r0			; say no errors
	$fetch	r1,RSZ,r1		; get the record size now
100$:	return

	global	<o$bkt>


	.sbttl	put a record to an rms sequential file


;	P U T R E C
;
;	putrec( %loc buffer, %val record_size, %val channel_number )
;
;	input:	@r5	address of user buffer
;		2(r5)	record size
;		4(r5)	channel number
;
;	output:	r0	rms sts
;
;	Write the next record to  a disk file.


putrec::mov	r1	,-(sp)
	mov	4(r5)	,r0		; get the channel number
	bne	5$			; if zero then assume TI:
	print	@r5	,2(r5)		; dump the buffer to ti: then
	br	100$			; and exit
5$:	asl	r0			; times 2 to index into table
	mov	rablst(r0),r1		; get the record access buffer
	$store	@r5  ,RBF,r1		; stuff a record buffer in
	$store	2(r5),RSZ,r1		; and a current record size
	cmp	filtyp(r0),#binary	; image mode today ?
	bne	10$			; no
	$store	#1000,RSZ,r1		; yes, insure block write
	clr	o$bkt+0(r1)		; yes, clear the VBN fields
	clr	o$bkt+2(r1)		; yes, clear the VBN fields
	$write	r1			; simple
	br	20$			; get the status and exit
10$:	$put	r1			; write a record now		   /SSH
20$:	$fetch	r0,STS,r1		; get the return STATUS field
	tst	r0			; did it work ?
	blt	99$			; no
	clr	r0			; say no errors
	br	100$
99$:	mov	r0,tmperr		; store error code for debugging
100$:	mov	(sp)+	,r1
	return


	.sbttl	getc	get one character from an input file


;	G E T C
;
;	getc(%val channel_number)
;
;	input:	@r5	channel_number
;	output:	r0	rms error status
;		r1	the character just read

getc::	mov	@r5	,r0
	call	getcr0
	return


fgetcr::save	<r2,r3>			; save temps
	mov	r0	,r2		; channel number please
	asl	r2			; times 2
	cmp	bufp(r2),#-1		; need to initialize the buffer?
	bne	10$			; no
	calls	getrec	,<buflst(r2),r0>; yes, load it please
	tst	r0			; did the read work ?
	bne	100$			; no, return rms error code
	clr	bufp(r2)		; it worked. clear current pointer
	mov	r1	,bufs(r2)	; and save the record size
	br	30$			; and goto common code

10$:	cmp	bufp(r2),#-2		; flag to return <cr> ?
	bne	20$			; no
	movb	#cr	,r1		; yes, return it in r1
	mov	#-3	,bufp(r2)	; and setup for a <lf> nexttime
	clr	r0			; no error
	br	100$			; bye

20$:	cmp	bufp(r2),#-3		; flag to return a <lf> ?
	bne	30$			; no
	movb	#lf	,r1		; yes, return <lf> in r1
	mov	#-1	,bufp(r2)	; flag buffer reload next time
	clr	r0			; no error
	br	100$


30$:	tst	bufs(r2)		; anything left to get in record?
	bne	40$			; yes
	mov	#-2	,bufp(r2)	; no, flag for a <cr> next
	cmp	filtyp(r2),#binary	; a binary file today ?
	bne	35$			; yes, need data as is please
	mov	#-1	,bufp(r2)	; yes, flag for a read next
35$:	mov	r2	,r0		; channel number please
	asr	r0			; NOT times two
	call	getcr0			; call ourselves to do it
	br	100$			; and exit

40$:	mov	buflst(r2),r3		; get the address of the buffer
	add	bufp(r2),r3		; and point to the next character
	clr	r1			; to be returned in r1
	bisb	@r3	,r1		; simple
	inc	bufp(r2)		; buffer.pointer := succ(buffer.pointer)
	dec	bufs(r2)		; amountleft := pred( amountleft )
	clr	r0			; no errors please

100$:	unsave	<r3,r2>
	return



	.sbttl	putc	put a single character to an rms file

;	P U T C
;
;	input:	@r5	the character to put
;		2(r5)	the channel number to use
;
;	Buffer single character i/o to internal disk buffer.
;	Buffer is dumped if internal buffer is  full or, for
;	FB$VAR records (default for TEXT), a carraige return
;	is found. For FB$VAR with FB$CR format, all carraige
;	returns  and line feeds are  flushed as  this record
;	format will have them put back later.
;	The local buffers are allocated in CREATE and OPEN.


putc::	save	<r1>			; simply save r1 and call putcr0
	mov	2(r5)	,r1		; to do it. putcr0 will be somewhat
	clr	r0			; faster to call directly due to the
	bisb	@r5	,r0		; overhead involved in setting up an
	call	putcr0			; argument list.
	unsave	<r1>			; pop saved r1 and exit
	return				; bye


putcr0::save	<r1,r2,r3,r4>		; save registers we use
	mov	r1	,r2		; channel number
	asl	r2			; times 2 of course
	cmp	filtyp(r2),#binary	; is this a binary file today ?
	beq	5$			; yes, don't dump buffer on <cr>
	cmpb	r0	,recdlm		; /56/ end of line time today ?
	beq	10$			; yes, dump the record out
5$:	cmp	bufp(r2),bufsiz(r2)	; is the buffer full ?
	blo	20$			; no, store some more characters in it
10$:	movb	r0	,r3		; yes, save the input character r0
	calls	putrec	,<buflst(r2),bufp(r2),r1> ; yes, dump the buffer please
	clr	bufp(r2)		; pointer := 0
	tst	r0			; did it work ?
	bne	100$			; no, die
	mov	buflst(r2),r4		; it worked. zero the buffer now
	mov	bufsiz(r2),r0		; get the buffer address and size
15$:	clrb	(r4)+			; for i := 1 to bufsiz
	sob	r0	,15$		;   do buffer[i] := chr(0)
	movb	r3	,r0		; ok, restore the old character

20$:	cmp	filtyp(r2),#binary	; once again, is this a binary file ?
	beq	30$			; yes, ignore checks for <LF> and ^Z.
	cmp	filtyp(r2),#terminal	; terminal file today ?
	beq	30$			; yes, we want cr's and lf's
	cmpb	r0	,#lf		; we simply like to ignore line feeds
	beq	90$			; bye
	cmpb	r0	,#'Z&37		; control Z ?
	beq	90$			; yes, ignore the control Z's please
	cmpb	r0	,#cr		; carraige return today ?
	beq	90$			; yes, ignore it
30$:	mov	bufp(r2),r1		; get the current buffer pointer
	add	buflst(r2),r1		; and point to a new home for the
	movb	r0	,@r1		; the input character in r0
	inc	bufp(r2)		; pointer := succ( pointer )

90$:	clr	r0			; no errors
100$:	unsave	<r4,r3,r2,r1>
	return

	GLOBAL	<recdlm>		; /56/


	.sbttl	flush


flush:	mov	@r5	,r0		; get the internal channel number
	asl	r0			; times 2 for indexing
	tst	bufp(r0)		; anything in the buffer
	beq	100$			; no
	tst	mode(r0)		; writing today ?
	beq	100$			; no
	calls	putrec	,<buflst(r0),bufp(r0),@r5> ; yes, dump it
	return
100$:	clr	r0
	return





	.sbttl	lookup	do a filename lookup, wildcarding supported
	.enabl	gbl


;	L O O K U P
;
;	input:	@r5	arg count	(DEC standard Fortran convention)
;		2(r5)	address of input string
;		@4(r5)	flag word for initializing with a $PARSE
;		6(r5)	address of output string
;
;	output:	r0	RMS error code
;
;
;	clr	index
;10$:	calls	lookup	,<#3,#inbuf,#index,#outbuf>
;	tst	r0
;	bne	100$
;	do something
;	br	10$




	.mcall	$parse	,$search,$store	,$fetch	,$compare
	.mcall	fab$b	,fab$e	,nam$b	,nam$e
	.mcall	$off	$testbits				;RBD01

	.save
	.psect	rmssup	,d



fab:	fab$b				; argument fab
	 f$nam	nam			; link to nam		;RBD01--
	 f$lch	1			; a dummy channel for the i/o op
	fab$e

nam:	nam$b				; nam definition
	 n$esa	expstr			; exp str address
	 n$ess	64.			; exp str length
	 n$rsa	resstr			; res str address
	 n$rss	64.			; res str length
	nam$e

expstr:	.blkb	64.			; context must be preserved here
resstr:	.blkb	64.			; a temp place for the result

	.restore


	.sbttl	the real work of lookup

	.psect	$pdata
					; Make this <> 0 if you can't do CALFIP
fu$dir::.word	0			; style wildcarding on your non-standard
					; RSTS system.  Could cause side effects
					; with remote decnet nodes.
	.psect	$code

lookup::tst	rsx32			; /56/ Ancient RSX today?
	beq	4$			; /56/ No
	mov	#ER$NMF	,r0		; /56/ Yes, preset No More Files
	tst	@4(r5)			; /56/ Second call?
	bne	3$			; /56/ Yes, die
	STRCPY	6(r5)	,2(r5)		; /56/ No just return the passed string
	inc	@4(r5)			; /56/ Note that we have been here
	clr	r0			; /56/ No errors
3$:	return				; /56/ Exit
					;
4$:	save	<r1,r2,r3,r4,r5>	; Save these please
	mov	#fab	,r1		; map the target fab	;RBD01--
	tst	fu$def			; do we really need a default device?
	beq	5$			; no
	$store	#sydisk,DNA,r1		; yes, please stuff the def device name
	$store	#sylen ,DNS,r1		; and the length of it also please
5$:	strlen	#defdir			; anything in the Kermit default dir?
	tst	r0			; if <> then use it
	beq	10$			; nothing there to use. Let system do it
	$store	#defdir	,DNA,r1		; something was there, stuff it in
	$store	r0	,DNS,r1		; and the length of the default
10$:	mov	r1	,r0		; save it for later
	mov	#nam	,r3		; map the target nam
	tst	@4(r5)			; first time thru needs a parse
	bne	40$			; not the first time

	clrb	expstr			; clear the expanded name and
	clrb	resstr			; the resultant string
	mov	2(r5)	,r4		; point to the filename passed
	mov	r4	,r1		; and save the pointer
20$:	tstb	(r1)+			; and get the length of the name
	bne	20$			; for an .asciz string
	sub	r4	,r1		; compute the length of the string
	dec	r1			; which is off by one
	$store	#lun.sr,lch,r0		; channel number please
	$store	r1,fns,r0		; stuff the filename length
	$store	r4,fna,r0		; and the filename address
	$parse	r0			; parse the strings
	$fetch	r4,sts,r0		; get error codes

	cmp	#ER$UIN,r4		; Maybe a remote file spec?    ;RBD01+
	bne	30$			; (no)
	$testbits  #<nb$wve!nb$wty!nb$wna!nb$wdi>,fnb,r3    ; Anything wild?
	bne	90$			; (wild remote files no good)
	$testbits  #nb$nod,fnb,r3	; Remote file?
	beq	90$			; (ER$UIN with no node???)
	$off	#nb$wch,fnb,r3		; Make succeeding $search's act nice
	$fetch	r0,esl,r3		; Pass back expanded string
	$fetch	r2,esa,r3		;  and skip the $search.
	br	70$						       ;RBD01-

30$:	tst	r4			; < 0 ?
	bmi	90$			; yes, error

;	This added edit 2.12 by BDN for those RSTS systems that totally
;	disallow directory lookups by modify the executive for non-priv
;	users.

40$:	tst	fu$dir			; in case george w. @ purdue
	beq	50$			; needs this due to a hacked up exec
	$testbits  #<nb$wve!nb$wty!nb$wna!nb$wdi>,fnb,r3    ; Anything wild?
	bne	50$			; yes, let the $search go on
	tst	@4(r5)			; if no wildcarding and we have
	beq	45$			; already been here then return
	mov	#ER$NMF	,r4		; no more files and exit
	br	90$			; bye
45$:	$fetch	r0,esl,r3		; no, skip the $search and get the
	$fetch	r2,esa,r3		; expanded string from $parse
	br	70$			; and copy it over now

;	End of option tp skip lookups for non-wildcarded filenames.


50$:	$search	r0			; get a matching file
	$fetch	r4,sts,r0		; get error codes
	;							       ;RBD01+
	; The following shouldn't have been necessary, as I
	; banged off the NB$WCH bit above. But ...
	;
	cmp	r4,#ER$UIN		; Remote file hacking?
	bne	60$			; (no)
	mov	#ER$FNF,r4		; Yes, no "more" files
	br	90$			; and exit

60$:	tst	r4			; < 0 ?			       ;RBD01-
	bmi	90$			; yes, error
	$fetch	r0,rsl,r3		; get the string length
	$fetch	r2,rsa,r3		; get the string address

70$:	mov	6(r5)	,r1		; where to return the string
80$:	movb	(r2)+	,(r1)+		; copy it over
	sob	r0	,80$		; for however the long it is
	clrb	@r1			; insure .asciz please
	clr	r0			; no errors
	inc	@4(r5)			; say we have at least one file
	br	100$			; and exit

90$:	mov	r4	,r0		; error, return it please
	br	100$			; exit

100$:	unsave	<r5,r4,r3,r2,r1>
	return



	.save
	.psect	rendat	,rw,d,lcl,con,lcl

	.mcall	$compare,$fetch	,$parse	,$search,$set	,$store
	.mcall	fab$b	,nam$b	,$rename

;	24-Jan-86  14:01:48 Rename, Delete and GMCR code moved to overlay


RNFAB1::FAB$B				; Old file name
	 F$NAM	RNNAM1			; Link to RNNAM1	       ;RBD01--
	 F$LCH	1			; Channel 1 (a dummy, filled in later)
	FAB$E

RNNAM1::NAM$B				; NAM definition
	NAM$E


RNFAB2::FAB$B				; New file name
	 F$NAM	RNNAM2			; Link to RNNAM2	       ;RBD01--
	 F$LCH	1			; a dummy channel
	FAB$E

RNNAM2::NAM$B				; NAM definition
	NAM$E


	.restore



	.sbttl	fparse	parse filename and fill in with defaults

	.mcall	$compar	,$fetch	,$off	,$parse	,$store
	.mcall	tlog$s

parfab	=	rnfab1
parnam	=	rnnam1


;	F P A R S E
;
;	input:	@r5	input filename,     .asciz
;		defdir	the default directory name string to use
;
;	output:	2(r5)	expanded filename, .asciz, maximum length 63 bytes
;		r0	error codes


tlog::	save	<r1,r2,r3>		; /46/ Save registers
	sub	#200	,sp		; /46/ Allocate a buffer
	mov	sp	,r3		; /46/ And a pointer to it please
	call	getsys			; /46/ Is this RSTS/E ?
	cmpb	r0	,#SY$RSTS	; /46/ If so, don't try TLOG$S out
	beq	100$			; /46/ Skip, must be RSTS/E
	strlen	(r5)			; /46/ Get length of input string
	TLOG$S	#0,ln$mk1,#0,(r5),r0,r3,#77,#tlogda,#tlogda+2
	cmpb	@#$DSW,#IS.SUC		; /46/ Did we get a translation?
	bne	100$			; /46/ No, exit this
	mov	r3	,r2		; /46/ Setup to make it asciz
	add	tlogda	,r3		; /46/ Add the translated string length
	clrb	(r3)			; /46/ in and insure it's .asciz
	strcpy	(r5)	,r2		; /46/ Copy new name over and exit
100$:	add	#200	,sp		; /46/ Pop local buffer
	unsave	<r3,r2,r1>		; /46/ Exit
	clr	r0			; /46/ No errors
	return				; /46/ Exit

	.save
	.psect	$PDATA
tlogda:	.word	0,0			; /46/ Returned data
ln$mk1::.word	0
	.restore


Fparse::tst	rsx32			; /56/ Old, old RSX?
	beq	1$			; /56/ No
	STRCPY	2(r5)	,@r5		; /56/ Yes, just copy the thing over
	clr	r0			; /56/ Success
	return				; /56/ Quick exit
1$:	save	<r1,r2,r3,r4>		; /46/ save registers we may overwrite
	mov	@r5	,r4		; /46/ Assume input from source
	call	getsys			; /46/ Is this RSTS/E ?
	cmpb	r0	,#SY$RSTS	; /46/ If so, don't try TLOG$S out
	beq	2$			; /46/ Skip, must be RSTS/E
	mov	2(r5)	,r3		; /46/ Address of a buffer to use
	strlen	r4			; /46/ Get length of input string
	TLOG$S	#0,ln$mk1,#0,r4,r0,r3,#77,#tlogda,#tlogda+2
	cmpb	@#$DSW,#IS.SUC		; /46/ Did we get a translation?
	bne	2$			; /46/ No, exit this
	mov	r3	,r4		; /46/ We did, set a new source address
	add	tlogda	,r3		; /46/ Add the translated string length
	clrb	(r3)			; /46/ in and insure it's .asciz
2$:	mov	#parfab	,r1		; point to the fab we use       ;RBD01--
	$store	#0,DNS,r1		; /42/ PLEASE clear this OUT!
	tst	fu$def			; do we need a defualt device string?
	beq	3$			; no
	$store	#sydisk,DNA,r1		; yes, please put it where we need it
	$store	#sylen ,DNS,r1		;      also, the length also
3$:	strlen	#defdir			; get the default directory spec
	tst	r0			; was anything there ?
	beq	4$			; no
	$store	#defdir,DNA,r1		; yes, stuff that in for the default
	$store	r0     ,DNS,r1		; name string, and stuff the length.
4$:	$store	#lun.sr,LCH,r1		; a channel number to use for $PARSE
	$off	#fb$fid,FOP,r1		; we want an implicit $SEARCH
	mov	#parnam	,r2		; also point to the NAME block
	sub	#100	,sp		; allocate result name string
	$store	sp  ,RSA,r2		; set up the pointer to name string
	$store	#100,RSS,r2		; and set the size of the string
	sub	#100	,sp		; allocate result expanded name string
	$store	sp  ,ESA,r2		; set up the pointer to expanded name
	$store	#100,ESS,r2		; and set the size of the string
	$store	#ER$FNM ,STS,r1		; preset a bad filename error
	strlen	r4			; /46/ get the length of the filename
	tst	r0			; anything left at all ?
	beq	90$			; no, fake a bad filename please
	$store	r0,FNS,r1		; stuff the filename size in please
	$store	r4,FNA,r1		; /46/ stuff the filename address
	$parse	r1			; try to parse the filename now

	$compar	#ER$UIN,sts,r1		; Maybe a remote file spec?    ;RBD01+
	bne	5$			; (no)
	$testb	#<nb$wve!nb$wty!nb$wna!nb$wdi>,fnb,r2    ; Anything wild?
	bne	90$			; (wild remote files no good)
	$testb	#nb$nod,fnb,r2	; Remote file?
	beq	90$			; (ER$UIN with no node???)
	$off	#nb$wch,fnb,r2		; Make succeeding $search's act nice
	br	7$			; Go ahead with it	       ;RBD01-

5$:	$compar	#0  ,STS,r1		; did the parse of the name work ?
	blt	90$			; no, exit and return STS in r0

7$:	mov	2(r5)	,r1		; where we will copy the name to
	movb	o$esl(r2),r0		; the length of the new name
	beq	30$			; can't happen unless you fubar
	cmp	r0	,#77		; truncate names that are too long
	blos	10$			; it's ok
	mov	#77	,r0		; too long, please set it to 63 (10)
10$:	mov	o$esa(r2),r2		; where the name is coming from
20$:	movb	(r2)+	,(r1)+		; copy a byte at a time please
	sob	r0	,20$		; next please
30$:	clrb	@r1			; insure .asciz please
	clr	r0			; no errors please
	br	100$			; bye

90$:	$fetch	r0,STS,r1		; error from parse, return in r0
100$:	add	#200	,sp		; pop local nameblock buffers
110$:	unsave	<r4,r3,r2,r1>		; /46/ pop registers
	return				; bye


	global	<defdir>
	GLOBAL	<RSX32>			; /56/


;	F I X W I L D
;
;	FIXWILD will replace % with ? for RSTS/E
;
;	input:	@r5	Address of string to process


fixwil::nop				; in case we want to patch to 207
	save	<r2>			; save a register we use here
	calls	getsys			; is this RSTS ?
	cmpb	r0	,#sy$rsts	;
	bne	100$			; no
	mov	@r5	,r2		; get the string address
10$:	tstb	@r2			; done with the filename yet ?
	beq	100$			; yes, exit
	cmpb	@r2	,#'%		; check for a % character
	bne	20$			; no
	movb	#'?	,@r2		; yes, replace with question mark
20$:	inc	r2			; next please
	br	10$			; back again
100$:	unsave	<r2>			; pop r2
	clr	r0			; no errors
	return				; bye
	


iswild::save	<r1,r2>			; save a register we may use
	mov	#parfab,r2		; get a fab to use for this
	tst	fu$def			; do we need a defualt device string?
	beq	5$			; no
	$store	#sydisk,DNA,r2		; yes, please put it where we need it
	$store	#sylen ,DNS,r2		;      also, the length also
5$:	strlen	#defdir			; get the default directory spec
	tst	r0			; was anything there ?
	beq	10$			; no
	$store	#defdir,DNA,r2		; yes, stuff that in for the default
	$store	r0     ,DNS,r2		; name string, and stuff the length.
10$:	$store	@r5,FNA,r2		; filename address
	strlen	@r5			; length
	$store	r0,FNS,r2		; into the FAB please
	$fetch	r1,NAM,r2		; get NAM block address
	clr	O$ESA(r1)		; no expanded string address
	clr	O$RSA(r1)		; no resultant string address
	clrb	O$ESS(r1)		; no length fields either
	clrb	O$RSS(r1)		; no length fields either
	$parse	r2			; parse the filename
	$fetch	r0,STS,r2		; get the status
	bmi	90$			; exit on error please
	$testbi #NB$WVE!NB$WTY!NB$WNA!NB$WDI,FNB,r1 ; any wildcarding today ?
	beq	90$			; no
	mov	#1	,r0		; yes, return(true)
	br	100$			; exit
90$:	clr	r0
100$:	unsave	<r2,r1>			; pop reg and exit
	return				; exit








	.sbttl	return current task size and return exec

	.mcall	gtsk$s	,gtim$s



second::save	<r2,r3>			; /43/ Get seconds past midnight
	sub	#40	,sp		; /43/ Used for reporting transfer
	mov	sp	,r2		; /43/ statistics
	gtim$s	r2			; /43/ One should really get the time
	mov	g.timi(r2),r3		; /43/ in the 64 bit klunk format to
	mul	#60.	,r3		; /43/ avoid 24 hour rollover, but
	add	g.tisc(r2),r3		; /43/ I really think this is
	mov	g.tihr(r2),r0		; /43/ sufficient
	clr	r1			; /43/ multiply hour of day by 3600
	mul	#60.*60.,r0		; /43/ which has to be 32 bits in
	add	r3	,r1		; /43/ size, then add in minutes*60
	adc	r0			; /43/ + seconds.
	add	#40	,sp		; /43/ Pop buffer and exit
	unsave	<r3,r2>			; /43/ Pop registers
	return				; /43/ Bye

;	G E T S Y S
;
;	output:	r0	operating system
;
;	sy$11m	(1)	for rsx11m
;	sy$ias	(3)	for ias
;	sy$rsts	(4)	for rsts
;	sy$mpl	(6)	for m+
;	sy$rt	(7)	for rt11 ????


getsys::sub	#40	,sp		; use the stack for a buffer
	mov	sp	,r0		; and point to it please
	gtsk$s	r0			; simple
	mov	g.tssy(r0),r0		; return exec
	add	#40	,sp		; pop buffer and exit
	return				; bye



	.sbttl	gsa	get space for i/o buffers


;	Modified from sample GSA from RMS v2 distribution
;	by Brian Nelson  05-Jan-84  10:22:06
;
;
;  Interface:
;    Request space:
;      R0 ->  RMS/user Pool list head (maintained by RL/CQB)
;      R1 :=  Amount of space requested (bytes)
;      R2 :=  0 (differentiates between request and release)
;
;    Release space:
;      R0 ->  RMS Pool list head (maintained by RL/CQB)
;      R1 :=  Amount of space to be released (bytes)
;      R2 ->  Base address (for release)
;
;
;  Returns:
;    C-Bit "set"   if an error has occurred (failure)
;    C-Bit "clear" if no error has occurred (success)
;


	.Mcall	Extk$S


	.Sbttl	Control block definitions

	.Psect	GSA$$D,RW,D

;
; GSA internal data:
;
;   GSABAS - Base address for the next memory allocation.
;            Initially set to zero, it will be assigned
;            the first address outside of the task's
;            current address limits.
;   GSAMIN - Decimal value reflecting the minimum size
;            (in bytes) to extend the task in order to
;            provide space to the pool.
;   GSAREQ - Requested pool block number.  If a request
;            for the 'GSAMIN' fails, then the original
;            allocation size will be attempted.  If that
;            fails, then there is no more memory left.
;

GSABAS::			; GSA base address
	.Word	000000		; (for next allocation)
GSAMIN::			; Minimum allocation
	.Word	512./64.	; (in 32-word blocks)
GSAREQ::			; Size of this request
	.Word	000000		; (if 'GSAMIN' extends fail)



	.Sbttl	GSA Initialization code

	.Psect	GSA$$I,RO,I


	.mcall	extk$s	,gtsk$s

GSAINI:
	Mov	R0,-(SP)	; R0-2 will be used to
	Mov	R1,-(SP)	; communicate with $INIDM
	Mov	R2,-(SP)	; NOTE: $INIDM uses EXTSK.
	mov	r0	,-(sp)	; save r0
	sub	#40	,sp	; check for 512 boundary
	mov	sp	,r0	; get the current task size and see
	gtsk$s	r0		; if we are at a boundary. if so, then
	mov	g.tsts(r0),r0	; extend a little bit to get INIDM to
	add	#40	,sp	; behave itself
	bic	#^c777	,r0	; strip all the high crap
	cmp	r0	,#776	; should we extend a little bit?
	blo	10$		; no
	extk$s	#1		; yes, get 64 more bytes please
10$:	mov	(sp)+	,r0	; restore r0

	Call	$INIDM		; Initialize dynamic memory
	Mov	R1,GSABAS	; Setup the "free" address
	Mov	(SP)+,R2	; Restore the registers
	Mov	(SP)+,R1	;
	Mov	(SP)+,R0	;
	Return			; And return to GSA



	.Sbttl	GSA Mainline code

	.Psect	GSA$$M,RO,I

;
; GSA Mainline
;
;   Entry point is "GSA", with registers 0-2 loaded as
;   described above.
;

GSA::
gsax:

;
; First, determine if dynamic memory has been initialized.
; GSABAS (initially set to zero) will be non-zero if $INIDM
; has been called and the memory list initialized.  On RSX
; based systems it is possible to install tasks with an
; extension (/INCREMENT).  $INIDM will detect this and setup
; the first memory entry in the pool list.
;
; A point to note: If the RSX task has been installed with
; the non-checkpointable (/-CP) flag, then EXTKs will not
; return success.  If it is necessary to install the task
; non-checkpointable, then the task should be installed with
; and increment value.
;

	Tst	GSABAS		; Dynamic memory initialized?
	Bne	10$		; Yes if NE, proceed
	Call	GSAINI		; Otherwise, initialize pool
10$:	Tst	R1		; Real memory?
	Bne	20$		; Yes if NE, then process it
	Return			; Otherwise return with success


20$:	Tst	R2		; Address specified? (release)
	Beq	30$		; No if EQ, then it's a request
	Jmp	$RLCB		; Otherwise it's a release; do it
30$:	Mov	R0,-(SP)	; save pool list head
	Mov	R1,-(SP)	; save size of request
	Mov	R2,-(SP)	; save entry flag
	Call	$RQCB		; Try the allocation
	Bcc	70$		; CC signifies success
	Mov	2(SP),R1	; Obtain the request size
	Add	#63.,R1		; Round the request
	Asr	R1		; to a 32-word boundary
	Asr	R1		; Then convert the value
	Asr	R1		; to the number of
	Asr	R1		; 32-word blocks.
	Asr	R1
	Asr	R1
	Mov	R1,GSAREQ	; Save the real size
	Cmp	R1,GSAMIN	; Smaller than minimum?
	Bhi	40$		; No if HI, use it as is
	Mov	GSAMIN,R1	; Otherwise use GSAMIN
40$:	Extk$S	R1		; Extend the task
	Bcc	60$		; CC if successful
	Cmp	R1,GSAREQ	; Is this request?
	Blos	50$		; Yes if LOS, the end
	Mov	GSAREQ,R1	; Otherwise try to use
	Br	40$		; the actual request
50$:	Sec			; Mark failure
	Br	70$		; And exit

60$:	Mov	4(SP),R0	; Setup the PLH
	Asl	R1		; Convert the real
	Asl	R1		; size to the actual
	Asl	R1		; 16-bit size that
	Asl	R1		; was allocated.
	Asl	R1		; The virtual address
	Asl	R1		; should be after the
	Mov	GSABAS,R2	; task (which is now
	Add	R1,GSABAS	; part of the task)
	Call	GSAX		; Call ourself to release
	Mov	(SP)+,R2	; Restore our registers
	Mov	(SP)+,R1	; to the initial state
	Mov	(SP)+,R0	; upon entry, and reenter
	Br	GSAX		; as if it's a new request

70$:	Inc	(SP)+		; These won't alter the
	Bit	(SP)+,(SP)+	; C-bit, so status remains
	Return			; unchanged upon return



	.sbttl	Corrected version of $INIDM

;	 Re-do $INIDM to use the  actual task top address,  not
;	that which was stored by TKB from the .LIMIT directive.
;	This is required because we have already done a EXTK$S.
;
;	17-Feb-87  07:11:21  BDN edit 3.56

	.mcall	GPRT$	,GTSK$	,DIR$	,GTSK$S
	.Save
	.psect	IMPURE	,d

Limit:	.Limit
pdpb:	GPRT$	tbuf
tdpb:	GTSK$	tbuf

tbuf:	.blkw	20

	.Restore

	.Psect	PURE$I	,RO,I,LCL,REL,CON

;	Inidm
;
;	Input:	r0	Address of free code pool listhead
;	Output:	r0	First address in task
;		r1	Address following task
;		r2	Size of core pool

$Inidm::DIR$	#tdpb			; We already did an EXTK$S so
	mov	tbuf+G.TSTS,r2		; want to use the CURRENT topmem
	add	#3	,r2		; Round up to next 4 byte boundary
	bic	#3	,r2		; ...
	mov	r2	,@r0		; Set base address of pool
	EXTK$S	#1			; Ask for just a little bit more
	DIR$	#pdpb			; Get partition parameters
	mov	$DSW	,r0		; Save starting address of partition
	DIR$	#tdpb			; Get task parameters
	mov	r2	,-(sp)		; Save starting address
	clr	(r2)+			; Clear out first word
	mov	tbuf+G.TSTS,(r2)	; Set physical size of task
	sub	r0	,(sp)		; Compute apparent size of task
	mov	r0	,r1		; Copy base address
	add	(r2)	,r1		; Next address after task
	sub	(sp)+	,(r2)		; Set size of free pool
	mov	(r2)	,r2		; Get size
	return				; And exit

	.end
