.title LNX -- DO: device interface to Linux .dsabl gbl .enabl lc .nlist bex ;+ ; ; File exchange program for ASCII/IMAGE transfer between RSX ; and Linux for E11 PCs. It can also list the Linux directory. ; ; Copyright (c) 1999-2005 by John Shilling & Associates, ; an unpublished work. ; ; John Shilling ; 28-Jan-1999 ; ; Adapted from: ; ; DOS file device handler for RT-11 V4.0 and later. ; By John Wilson. ; Copyright (C) 1998 by Digby's Bitpile, Inc. DBA D Bit. ; All rights reserved. ; ; DOS program (DOS <--> RSX file transfer program) adapted ; for Linux ; ; This program accesses Linux files using the DO: file device in Ersatz-11. ; It allows only one file at a time to be read or written. The file ; must be located in the current directory, and has to have an 9.3 ; filename with no non-RAD50 characters. ; ; 8-Dec-2000 Expand buffer length ; Use 32-bit math for disk address ; Make length argument a variable ; Conditionally make transfer faster (see OLDWAY) ; ; 11-Mar-2002 Added E11 Command Interface Switch (/X cmd-line) ; ; 19-Mar-2003 Changed "In Use" vector check to compare to same ; as @4 (=OD trap) instead of to between $NS0 and ; $NS7 for compatibility between releases. ;- ; ; RSX System macros ; .mcall mrkt$s, wtse$s, exit$s, dir$ .mcall fcsmc$, fcsbt$, fdof$l fcsmc$ fcsbt$ ;the FCS kitchen sink fdof$l fsrsz$ 1 ie.eof = -10. ;they forgot this one... UISAR0 = 177640 ; ; Externals from Executive Symbol Table ; .globl $DSW ; ; Internal macros ; .macro mova arg ;mov our address to absadr doubleword mov arg,-(sp) jsr pc,cvtadr .endm .macro mess arg ;type a message mov #arg,-(sp) jsr pc,typit .endm mess .macro fatal arg ;fatal message mov #arg,-(sp) jsr pc,die .endm fatal ; ; DO: Device CSR bits: ; dovec= 400 ;7-bit vector/4 starts with this bit dopri= 20 ;3-bit interrupt priority (4-7) starts with this bit dobsy= 4 ;NZ => device busy dogo= 2 ;set to start command doie= 1 ;int enable ; ; Function codes (for CMDCMD field in command packet): ; doe11= -1 ;inject E11 command doopn= 0 ;open file docrt= 1 ;create (but don't open) file dodel= 2 ;delete file dordd= 3 ;read data dowrd= 4 ;write data dosek= 5 ;seek dofst= 6 ;find first wildcard match donxt= 7 ;find next wildcard match docls= 8. ;close file ; ; Use a standard CSR and vector ; do$csr = 176470 ;;do$vec = 240 ;in use! do$vec = 274 ;Free on our system... do$ba= do$csr+2 ;bus addr reg do$bae= do$csr+4 ;bus addr ext reg ; ; Define the DOS <-> RSX Buffer Length ; nbblok = 8. ;# of blocks ;+ ; ; Impure Storage ; ; Note: Adjacency assumed in all of the below! ;- ; base = . ;virtual base of program when running absadr: 0,0 ;absolute address of our address of something savvct: 0,0 ;saved vector address ferr: 0 ;RSX generated error code mode: 0 ;0=ASCII, 1=image func: 0 ;1=read, -1=write other: 0 ;1=directory cmdpkt: ; command packet goes here cmdcmd: .blkw ;command code, 0-8. cmdsts: .blkw ;status (-1=timeout, 0=OK, >0=DOS err) cmdhnd: .blkw ;DOS file handle cmdprm: .blkw ;parameter (if defined by cmd) cmdlen: .blkw ;length of data buffer in bytes cmdba: .blkw 2 ;22-bit absolute addr of data buffer cmdbae = cmdba+2 hnd: .word 0 ;DOS handle for file flg: .word 0 ;NZ if handle is valid (0 => opened raw dev) ; fdb: fdbdf$ ;RSX general-purpose File Descriptor Block fdat$a r.fix,fd.blk,512.,32.,64. fdrc$a ,fcsbuf,512. fdop$a 1,dspt0 dspt0: 0,0 ;default device 0,0 ;default UIC dspt: 0,rfile ;default filename blkno: 0,0 ;the block in question iobuff: .blkw 256.*nbblok ;"nbblok"-block transfer buffer rsxmod: 0 ;NZ if it's from a GCML$ gcml: .byte 127.,41. ;QIO for get command line rsxcmd: ;data goes here ;GMCR line fcsbuf: .blkw 256. ;RSX/FCS file buffer .blkb 2 ;space for CR/LF crjt: 0 ;NZ if last char was CR file: .blkw 10./2 ;path/filename buffer for Linux .blkb 128.-10. ;more space for pathname in DOFST/DONXT lfile= .-file ;length of buf efile: .blkb ;guaranteed NUL at end .even rfile: .blkw 41. ;FILENAME.EXT buffer for RSX ;must be after "file" buffer lpath: .word rfile ;Points to Linux path ; ; Start the program ; start: finit$ ;Init FCS impure area cmp @#do$vec,@#4 ;see if vector is in use bne 10$ ;no, OK fatal vecuse ;Vector is in use! 10$: call dosatt ;attach the DOS file device again =. ;entry after LNX /X completion 15$: call getopr ;get the next command bcs 90$ ;error call deccmd ;decode command bcc 20$ ;ok mess invcmd ;else bad command br 15$ ;try again 20$: call decfnm ;decode filename bcc 30$ ;ok mess invnam ;bad name br 15$ ;try again 30$: tst func ;see if read or write blt 60$ ;if write, enter file bgt 50$ ;if read, lookup file tst other ;other function? beq 15$ ;no call direct ;else it's a directory mess opcomp ;it is done br 15$ 50$: call readfl ;read it br 80$ 60$: call writfl ;write it 80$: bcc 15$ ;ok mess opfail ;else it failed. br 15$ 90$: call dosdet ;detach DOS device exit$s ;+ ; Read a file from DOS, write to RSX ;- readfl: call lookup ;find the file bcs 80$ ;error clr blkno ;start with 1st DOS block clr blkno+2 ; clr fdb+f.fver ;always a new version fdat$r #fdb,,,,#32.,#64. ;large alloc and extent tst mode ;ASCII mode? beq 105$ ;yes mov #r.fix,(r0) ;no, image mode mov #512.,f.rsiz(r0) ;set fixed record length open$w ;open the RSX file bcs 70$ ;error ; ; read blocks ; 10$: call reados ;read DOS to IOBUFF bcc 12$ ;OK cmpb ferr,#ie.eof ;EOF? bne 60$ ;no tst r5 ;any bytes? beq 100$ ;no, all OK call padzro ;zero-fill last block 12$: mov #nbblok,r4 ;max blocks to write add r4,blkno ;next chunk next time adc blkno+2 ; mov #iobuff,r1 ;address of buffer 15$: mov r5,r2 ;length remaining cmp r2,#512. ;more than 1 block? ble 20$ ;no mov #512.,r2 ;yes 20$: put$ #fdb,r1,r2 ;put RSX bcs 90$ ;error sub r2,r5 ;more to go? ble 10$ ;no add r2,r1 ;yes dec r4 ;failsafe count... bgt 15$ ;continue br 10$ ;go again 60$: mess dosgte ;DOS read error br 95$ 70$: mess rsxope ;RSX open error br 95$ 80$: mess file mess dosope ;DOS open error br 95$ trsxpe =. 90$: mess rsxpte ;RSX write error 95$: call 101$ ;close it sec return 100$: mess opcomp ;Complete! 101$: mov #fdb,r0 ;close the file call .trncl ; .globl .trncl call close ;close the DOS file too clc return ; do ASCII mode 105$: mov #fd.cr*400+r.var,(r0) ;set variable length clr f.rsiz(r0) ;no record length yet open$w ;open the RSX file bcs 70$ ;error mov #fcsbuf,r3 ;init the output address clr crjt ;init flag for cr/lf ; ; read blocks ; 110$: call reados ;read DOS to IOBUFF bcc 112$ ;OK cmpb ferr,#ie.eof ;EOF? bne 60$ ;no tst r5 ;any bytes? beq 180$ ;no, all OK 112$: add #nbblok,blkno ;next chunk adc blkno+2 ; mov #iobuff,r1 ;address of buffer ; next output byte 115$: movb (r1)+,r2 ;get a byte beq 150$ ;ignore NULL cmpb r2,#15 ;izit CR? beq 130$ ;if so, write the record cmpb r2,#12 ;izit LF? bne 125$ ;no cmp crjt,#12 ;2 LF in a row? beq 120$ ;yes, output it tst crjt ;LF after CR? bne 160$ ;yes, no need to output a record 120$: mov #11,crjt ;make the flag into LF next br 140$ ;no, we must output a record 125$: movb r2,(r3)+ ;place in FCS buffer clr crjt ;last byte was not a CR cmp r3,#fcsbuf+510. ;long record? blo 150$ ;no ;yes, split the record if too long 130$: tst crjt ;two CR in a row? bne 150$ ;yes 140$: call putfcs ;write the record inc crjt ;we just "wrote" a CR 150$: dec r5 ;more in buffer? bgt 115$ ;yes br 110$ ;no, read DOS file 160$: clr crjt ;clear after seeing LF br 150$ ;continue 180$: cmp r3,#fcsbuf ;null buffer at end? beq 190$ ;yes call putfcs ;no, write last record 190$: br 100$ ;and done! ; output one text-editor-compatible record to RSX file putfcs: sub #fcsbuf,r3 ;compute length ;; beq 5$ ;no blank lines... put$ #fdb,#fcsbuf,r3 ;output one record bcs 10$ ;file write error 5$: mov #fcsbuf,r3 ;re-point to start of buffer return ;and done 10$: tst (sp)+ ;return to mainline br trsxpe ; ; zero-fill the last 512-byte segment padzro: mov #iobuff,r1 ;address of buffer add r5,r1 ;point past the filled part 10$: bit #777,r5 ;EOB? beq 30$ ;yes clrb (r1)+ ;no, pad one inc r5 ;extend length br 10$ ;go again 30$: return ;+ ; subroutine to read open DOS file ; returns R5 = BC ;- reados: clr r5 ;no length yet call seek ;set up "seek" command bcs 60$ ;(no open file, skip) call docmd ;send it bcs 40$ ;failed call addr ;load up buffer addr mov #dordd,cmdcmd ;set command call docmd ;do command bcs 40$ mov cmdlen,r5 ;get actual length beq 30$ ;EOF, special mov r5,r4 ;copy sub #512.*nbblok,r4 ;test bytes read beq 20$ ;if eq, request satisfied by bytecount ;short read, indicates EOF on DOS file 30$: movb #-10.,ferr ;show EOF error sec 20$: return ;done 40$: movb #-4,ferr ;show unrecoverable error br 30$ 60$: movb #-42.,ferr ;no open file br 30$ ;+ ; Write a file to DOS. Read it from RSX. ;- writfl: clr blkno ;start with 1st DOS block clr blkno+2 ; call nulfil ;convert filename, see if it's null bcs 80$ ;yes clr fdb+f.fver ;always a new version mov #512.,fdb+f.urbd ;allow a 512-byte file opns$r #fdb ;lookup the file on RSX bcs 80$ ;error call enter ;create DOS file bcs 70$ ;failed mov #iobuff,r1 ;address of buffer tst mode ;ASCII mode? beq 10$ ;yes mov #fdb,r0 ;restore R0! mov #512.,f.rsiz(r0) ;change to 512-byte records mov #r.fix,(r0) ; ; ; read RSX records, write DOS blocks ; 10$: call readrs ;read RSX to fcsbuf bcs 60$ ;EOF/error ;r5 has bytecount 20$: cmp r1,#iobuff+<512.*nbblok> ;output full? blo 30$ ;no call wridos ;yes, write DOS buffer bcs 75$ ;error 30$: movb (r2)+,(r1)+ ;copy RSX byte to DOS buffer dec r5 ;RSX buffer done? bgt 20$ ;no br 10$ ;yes 60$: cmpb f.err(r0),#ie.eof ;EOF? beq 90$ ;yes, OK mess rsxgte ;RSX read error call wridos ;dump DOS buffer bcs 75$ ;error on DOS too! br 95$ ;else done 70$: mess dosope ;DOS open error br 95$ 75$: mess dospte ;DOS write error br 95$ 80$: mess rsxope ;RSX open error br 95$ 90$: call wridos ;write last DOS buffer bcs 75$ ;error br 100$ ;done 95$: call 101$ ;close it sec return 100$: mess opcomp ;Complete! 101$: close$ #fdb ;close the file call close ;close the DOS file too clc return ;+ ; read RSX file using FCS, convert to stream ; readrs: mov #fcsbuf,r2 ;point to my buffer get$ #fdb,r2,#512. ;get a record mov f.nrbd(r0),r5 ;get length bcs 80$ ;error bitb #fd.cr,f.ratt(r0) ;do we need a CRLF at the end? beq 80$ ;no ;;* Patch out CR/LF for Linux -- just xfer ;; movb #15,fcsbuf(r5) ;yes, place it ;; movb #12,fcsbuf+1(r5) ; ;; add #2,r5 ;adjust length, can't overflow movb #12,fcsbuf(r5) ;yes, place it inc r5 ;; ** End patch 80$: return ;return cc/cs ;+ ; subroutine to write to open DOS file ; R1 points to end of buffer to write ;- wridos: call seek ;set up "seek" command bcs 30$ ;(no open file, skip) call docmd ;send it bcs 20$ ;failed call addr ;load up buffer addr sub #iobuff,r1 ;compute length mov r1,cmdlen ;length ble 5$ ;nothing to do mov #dowrd,cmdcmd ;set command call docmd ;do command bcs 20$ ;error add #nbblok,blkno ;advance block to put adc blkno+2 ; 5$: mov #iobuff,r1 ;reset buffer address 10$: return doerr =. 20$: movb #-53.,ferr ;say fatal error 25$: sec return 30$: movb #-42.,ferr ;say no open file br 25$ ;+ ; Close open file. ;- close: call gethnd ;get file handle bcs 10$ ;not open mov #docls,cmdcmd ;func=close call docmd ;close the handle 10$: return ;+ ; Delete a file. At present, this is not referenced. ;- delete: call getnam ;convert filename mov #dodel,cmdcmd ;func=delete call docmd ;execute it, come back on interrupt bcs doerr ;error return ;+ ; Look up an existing file. ;- lookup: call nulfil ;see if it's null bcs 40$ ;yes mov #1,cmdprm ;access=RO, sharing=compatibility mode clr cmdcmd ;func=open call docmd ;execute it bcs 40$ ;error call savhnd ;save handle clc return operr =. 40$: movb #-26.,ferr ;no such file sec return ;+ ; Enter a new file. ;- enter: mov #docrt,cmdcmd ;func=create call docmd ;execute it, come back on interrupt bcs operr ;error clr cmdprm ;access=RW, sharing=compatibility mode clr cmdcmd ;func=open call docmd ;execute it, come back on interrupt bcs operr ;error call savhnd ;save handle 10$: clc return ;+ ; Handle directory reads. ; ; We read filenames from the host OS one at a time. ; Unfortunately we get no size/date information. ; ;- direct: ;get the directory search started call getnam ;put name in buffer mov #dofst,cmdcmd ;command=find first match br 30$ ;skip 20$: ; retrieve next filename mov #donxt,cmdcmd ;command=find next match 30$: mov #file,r5 ;point at buf mova r5 mov absadr,cmdba ;set addr mov absadr+2,cmdbae mov #lfile,cmdlen ;length of buf call docmd ;get next dir entry bcs 80$ ;failed clrb efile ;guarantee terminating NUL mess file ;show on tty br 20$ ;back for next file 80$: return ;and done! ;+ ; Set up a "seek" command packet for file addr of blkno ;- seek: call gethnd ;get handle bcs 10$ ;not open mov r0,-(sp) ;save 2 mov r1,-(sp) mov blkno+2,r0 ;get starting block # mov blkno,r1 ; ashc #9.,r0 ;* 512 = file address mov r1,cmdba ;set low addr mov r0,cmdbae ;set high address clr cmdprm ;seek from BOF (C=0) mov #dosek,cmdcmd ;[func=seek] mov (sp)+,r1 ;restore 2 mov (sp)+,r0 10$: rts pc ;+ ; Load up address (etc.) information for DOS file device access. ;- addr: mova #iobuff ;address of the DOS buffer mov absadr,cmdba ;save addr mov absadr+2,cmdbae ;high bits too mov #512.*nbblok,cmdlen ;length rts pc ;+ ; ; Get file handle for open file. ; ; Returned in CMDHND, or C=1 if raw device or no file. ; ; R0 trashed, others preserved. ; ;- gethnd: tst flg ;could there be file open? beq 10$ ;no mov hnd,cmdhnd ;yes, fetch the handle tst (pc)+ ;C=0, skip SEC 10$: sec ;no file rts pc ;+ ; Save file handle for newly opened file. ; ; R0 trashed, others preserved. ;- savhnd: inc flg ;say open file mov cmdhnd,hnd ;save handle rts pc ;+ ; ; Parse filename, see if they're opening the null filename. ; ; Return C=1 if so (or if out of stack space), stack entry created. ; C=0 if not, so open the file and add its stack entry. ; ;- nulfil: call getnam ;convert filename cmp cmdlen,#1 ;anything besides the "." we added? bgt 20$ ;yes, C=0 clr flg ;say no open file 10$: sec 20$: rts pc ;+ ; Set address of filename in command buffer ;- getnam: mov #file,r4 ;point at filename buf mova r4 ;set up its address mov absadr,cmdba ;set addr mov absadr+2,cmdbae mov lpath,r3 ;set up path for this command clr cmdlen ;compute its length 5$: movb (r3)+,(r4) ;string done? beq 10$ ;yes cmpb (r4)+,#100 ;change filename blo 7$ ; to cmpb -1(r4),#132 ; lower? bhi 7$ ;no bisb #40,-1(r4) ;yes 7$: inc cmdlen ;no br 5$ 10$: return ;+ ; Do the current command, return when done. ;- docmd: mova #cmdpkt ;point at packet buf mov absadr,@#do$ba ;set packet addr mov absadr+2,@#do$bae mov #do$vec,r0 ;get vector asr r0 ;/4 asr r0 swab r0 ;in LH bis #<4*dopri>!dogo,r0 ;set PRI=4, GO, no IE mov r0,@#do$csr ;start command mov #100.,r0 ;start failsafe timer 5$: .if df OLDWAY mrkt$s #1,#1,#1 ;wait a tick... wtse$s #1 bit #dogo,@#do$csr ;still busy after this? beq doint ;no, done .iff bit #dogo,@#do$csr ;busy? beq doint ;no, done mrkt$s #1,#1,#1 ;wait a tick... wtse$s #1 .endc dec r0 ;wait more? bgt 5$ ;yes ;;; no way to abort cmd in progress? clr @#do$csr ;kill ints sec ;no rts pc ;return to caller ;+ ; "Interrupt" service routine. ;- doint: clr @#do$csr ;kill further ints cmp #1,cmdsts ;C=1 if CMDSTS is non-zero rts pc ;process result ;+ ; make an address within our task an absolute address ; ; 2(sp) = address (popped off upon return) ;- cvtadr: mov r0,-(sp) ;save a couple mov r1,-(sp) mov 6(sp),r1 ;get our address ashc #4,r0 bic #^c<16>,r0 ;use word indexed APR mov uisar0(r0),r1 ;get base segment address clr r0 ; ashc #6,r0 ;convert to 22-bit address mov r0,absadr+2 ; mov r1,absadr ;store mov 6(sp),r1 ;get our address again bic #160000,r1 ;use offset without APR add r1,absadr ;compute physical address adc absadr+2 ;(shouldn't need this) mov (sp)+,r1 ;restore 2 mov (sp)+,r0 ; mov (sp)+,(sp) ;adjust return address return ;and done! ;+ ; "attach" the DOS device ;- dosatt: mov @#do$vec,savvct ;save the original vector mov @#do$vec+2,savvct+2 mov @#4,@#do$vec ;make any interrupt trap to 4 mov @#6,@#do$vec+2 return ;+ ; "detach" the DOS device ;- dosdet: tst savvct ;vector saved? beq 10$ ;no mov savvct,@#do$vec ;restore prior vector mov savvct+2,@#do$vec+2 ; 10$: return ;+ ; Decode the command ;- deccmd: call nxnbl ;next non-blank bcs 7$ ;error clr func ;assume nothing clr other ; cmpb r2,#'/ ;Only a switch? beq 40$ ;Yes, assume it's an E11 command call nxbln ;next blank bcs 3$ ;none means no filename cmpb r2,#'G ;Get? beq 10$ ;yes cmpb r2,#'P ;Put? beq 20$ ;yes 3$: cmpb r2,#'D ;Directory? bne 5$ ;no inc other ;yes, it's a directory return 5$: sec 7$: return 10$: inc func ;it's a read return 20$: dec func ;it's a write return 40$: call nxnbl ;next character bcs 7$ ;none cmpb r2,#'X ;execute something? bne 5$ ;no call nxbln ;skip spaces bcs 7$ ;cs means no command tst (sp)+ ;return to mainline mov r1,r0 ;copy 45$: tstb (r0)+ ;skip to end bne 45$ sub r1,r0 ;find length dec r0 ; without the null mova r1 ;figure the absolute address ; fill in command packet mov absadr,cmdba ;set addr mov absadr+2,cmdbae mov #doe11,cmdcmd ;command=inject E11 command mov r0,cmdlen ;length call docmd ;do the command jmp again ;start all over ;+ ; Decode the filename ;- decfnm: clr mode ;assume ascii mode mov #rfile,r4 ;put 'em here mov r4,lpath ;assume no separate path clr r3 ;no valid characters yet call nxnbl ;advance to non-blank bcc 5$ ;if any tst other ;a directory? beq 80$ ;no mov #"*.,(r4)+ ;init to "*.*"<0> mov #'*,(r4)+ clr (r4)+ ; mov #4,r3 ;set the length clc ;it's OK return 5$: call israd ;valid filename character? bcs 20$ ;no movb r2,(r4)+ ;place in buffer inc r3 ;count call nxnbl ;next character bcs 30$ ;done cmp r3,#9. ;all we can take? blo 5$ ;no 20$: cmpb r2,#'. ;izit extension? bne 80$ ;no, it's bad! movb r2,(r4)+ ;place in buffer clr r3 ;go again call nxnbl ;next character bcs 30$ ;no more, it's OK 25$: call israd ;valid filename character? bcs 30$ ;no movb r2,(r4)+ ;place in buffer inc r3 ;count call nxnbl ;next character bcs 30$ ;done cmp r3,#3. ;all we can take? blo 25$ ;no 30$: clrb (r4)+ ;null after name sub #rfile+1,r4 ;compute length bmi 35$ ;bad only if R4 is a path mov r4,dspt ;set length of RSX filename 35$: tstb r2 ;more stuff in buffer? beq 60$ ;no, we're done cmpb r2,#'/ ;switch coming? bne 80$ ;no, error call nxnbl ;next character bcs 80$ ;must be something cmpb r2,#'I ;image? beq 40$ ;yes cmpb r2,#'B ;binary? beq 40$ ;yes cmpb r2,#'A ;ASCII? beq 50$ ;yes cmpb r2,#'P ;Path? beq 100$ ;yes br 80$ ;no 40$: inc mode ;set binary mode br 55$ 50$: clr mode ;set ascii mode 55$: call nxnbl ;seeif any more switches bcc 35$ ;yes 60$: clc ;everything cool! return 80$: sec ;something bad... return ; ; Process the PATH switch -- allow anything until blank in the string ; 100$: mov #file,r4 ;reset the output mov r4,lpath ;point this to the path too clr r3 ;reset the length call nxnbl ;get a non-blank character bcs 80$ ;no more - bad movb r2,(r4)+ ;copy string 105$: cmpb (r1),#40 ;at EOS? beq 110$ ;yes call nxnbl ;no, get the character bcs 30$ ; movb r2,(r4)+ ;copy to output br 105$ ; (no translation except TOUPPER) 110$: call nxnbl ;advance to non-blank br 30$ ;see if a switch ; scan for next word .enabl lsb nxnbl: tstb (r1) ;is there a character? beq 80$ ;no cmpb (r1),#40 ;some ctrl character? bhi 10$ ;no tstb (r1)+ ;yes, skip it br nxnbl 10$: movb (r1)+,r2 ;get the character cmpb r2,#140 ;lower? blo 15$ ;no bicb #40,R2 ;toupper 15$: clc ;good return 80$: clr r2 ;null character sec ;there isn't any more return ; scan for end of word nxbln: tstb (r1) ;is there a character? beq 80$ ;no cmpb (r1),#40 ;some ctrl character? blos 15$ ;yes tstb (r1)+ ;no, skip it br nxbln .dsabl lsb ; is character in R2 a radix-50 character? israd: cmpb r2,#'Z ;gt Z? bgt 50$ ;yes, bad cmpb r2,#'A ;lt A? bge 30$ ;no, it's good ;try number cmpb r2,#'9 ;gt 9? bgt 50$ ;yes, bad cmpb r2,#'0 ;lt 0? bge 30$ ;yes, in numeric range tst other ;in a directory? beq 50$ ;no cmpb r2,#'* ;wildcard? bne 50$ ;no, bad 30$: tst (pc)+ ;skip bad return 50$: sec ;set bad return return ;done ;+ ; Go away ;- die: mov 2(sp),r0 ;Print the message call typ1 bail: call dosdet ;kill DOS device close$ #fdb ;close RSX file exit$s ;+ ; Get a command line from user or the CLI ;- getopr: tst rsxmod ;is this command mode? bgt bail ;yes, no further commands dir$ #gcml ;first, try command line bcc 20$ ;ok 5$: mess prompt ;Prompt for a function and filename mov #io.rvb,qfn ;next, try a read .globl io.rvb mov #rsxcmd,r1 ;point to command buffer mov #"LN,(r1)+ ;Simulate the command prefix mov #"X ,(r1)+ ; mov r1,qbf ;Set up read terminal QIO mov #76.,qln ; mov #40,qcc dir$ #qm ;issue the read bcs 80$ ;if cs, this is fatal tstb qiosb ;check for ctrl-Z ble 80$ ;must be... mov qiosb+2,r0 ;get the length beq 5$ ;nothing on line add r1,r0 ;point past buffer movb #15,(r0)+ ;place CR inline clrb (r0)+ ;null at end call nxnbl ;anything on line? dec r1 ;back up for next caller bcs 5$ ;no command on the line. dec rsxmod ;not gcml$ mode return ;return CC 20$: mov #rsxcmd+3,r1 ;point past cmd name 25$: call nxbln ;look for a blank bcs 5$ ;none call nxnbl ;anything on line? dec r1 ;back up for next caller bcs 5$ ;no command on the line. inc rsxmod ;yes, it's from a GCML$ return 80$: sec ;some error... return ;+ ; Type a message on user's terminal ;- typit: mov 2(sp),r0 typ1: mov r0,qbf 5$: bitb #177,(r0) ;end? beq 20$ ;yes tstb (r0)+ ;no, count it br 5$ 20$: mov #40,qcc ;assume normal tstb (r0) ;izit normal? beq 30$ ;yes clr qcc ;no, so no car.ctl here 30$: sub qbf,r0 ;compute length mov r0,qln ;set length mov #io.wvb,qfn ;set write function .globl io.wvb dir$ #qm ;write it mov (sp)+,(sp) ;pop arg. return ;done ; ; RSX Terminal I/O ; qm: .byte 3,14 ;QIOW$ qfn: io.wvb,5,1,qiosb,0 ;to user's terminal qbf: 0 ;the buffer qln: 0 ;the length qcc: 0 ;the carriage control 0,0,0 ;garbage words qiosb: 0,0 ;the status ; ; Messages ; opfail: .asciz "Operation failed!" invnam: .asciz "Invalid Filename" vecuse: .asciz "Sorry, DO: vector is in use" invcmd: .ascii "Usage: LNX {GET | PUT | DIR} FILENAME.EXT [/A | /I /P]"<15><12> .asciz " -or- LNX /X E11-command-line-text" prompt: .asciz <15><12>"LNX> "<200> rsxope: .asciz "RSX file open error" dosope: .asciz "Linux file open error" rsxpte: .asciz "RSX file write error" rsxgte: .asciz "RSX file read error" dospte: .asciz "Linux file write error" dosgte: .asciz "Linux file read error" opcomp: .asciz "Operation Complete!" .even .end start