.title KRTCVT File name and misc data conversions .ident "V03.62" ; /62/ 27-Jul-93 Billy Youdelman ; ; increase size of fixfil stack buffer to SVID limit ; /BBS/ 1-Dec-91 Billy Youdelman V03.61 ; ; added useful RT-11/TSX+ binary file types ; modified chkext to handle file types of less than 3 chars ; fixfil - parse a device name in filespec, fixed termination bug ; namcvt now catches unix "/" and pc "\" directory delimiters ; namcvt fixed to not output a "." on a null input file name ; Copyright 1984 Change Software, Inc. ; ; 20-Mar-84 11:31:06 Brian Nelson ; ; Attempt to parse filespecifications that may include DECNET ; remote node name and directories in a manner compatible ; with RSTS, RSX and RT-11. ; ; This was first implemented using the host executives file ; name parsing services, ie for RSTS using the .FSS directive ; and for RSX using CSI and .PARSE to get the ; filespecification converted into rad50 and then converting ; back to ascii. The problem with doing it that way, apart ; from being a hack, is that we could not process DECNET node ; file specifications as the format of remote file names can ; never be expected to be compatible with the host system. ; Bob Denny wrote a new one for RSX which avoided this ; problem, and this version should work on all PDP-11 ; operating systems. ; ; This is implemented using a transition state table driver ; thus allowing simple modification to accommodate the various ; types of node file names that may come up in the future. ; ; For the time being this routine will be placed in the over- ; lay region ERRDVR, since as of now it is only called from ; KRTPAK and then only once for each file send to the remote ; system or micro. .include "IN:KRTMAC.MAC" .iif ndf KRTINC .error <; .include for IN:KRTMAC.MAC failed> .macro chtype ch,val ; /62/ work around "n/df" hosing .LST . = chtype+ch ; put in the buffer, according to its .byte val ; ascii value as an offset into it .endm chtype .psect chtype ,ro,d,lcl,rel,con .sbttl Generate character class table for file name state parsing chtype: .rept 128. .byte 0 ; everything inits to being ignored .endr chtype 0 ,1 ; exit on null chtype lf ,1 ; /62/ exit on a line feed chtype cr ,1 ; exit on chtype space ,7 ; spaces can be anywhere chtype '( ,2 ; start of a rsts style ppn chtype ') ,3 ; end of a ppn chtype comma ,6 ; part of a uic or ppn chtype '. ,5 ; part of a file name or directory chtype '/ ,4 ; /BBS/ end of a unix directory $ch = '0 ; /62/ digits are ok most anywhere .rept 10. chtype $ch ,7 $ch = $ch+1 .endr chtype '< ,2 ; start of a TOPS-20 directory chtype ': ,4 ; end of a device or node chtype 73 ,1 ; exit on ";" version delimiter chtype '> ,3 ; end of a TOPS-20 directory $ch = 'A&137 ; letters are also ok most anywhere .rept 32 chtype $ch ,7 $ch = $ch+1 .endr chtype '[ ,2 ; start of a directory or uic chtype '\ ,4 ; /BBS/ end of a pc directory chtype '] ,3 ; end of a directory $ch = 'a!40 ; don't forget lower case letters .rept 32 chtype $ch ,7 $ch = $ch+1 .endr .psect $pdata .sbttl NAMCVT state transition table ; note: "<" , "(" are mapped the same as "[" ; ">" , ")" are mapped the same as "]" ; all characters that map to zero are ignored by the parser ptable: ; char other null '[ '] ': '. ', letter/digit .byte 1 ,30. ,2 ,-1 ,11. ,21. ,-1 ,21. ; init .byte 2 ,30. ,-1 ,3 ,-1 ,2 ,2 ,2 ; [ ] .byte 3 ,30. ,-1 ,-1 ,14. ,23. ,3 ,23. ; [ ]xxx .byte 4 ,30. ,30. ,-1 ,-1 ,24. ,-1 ,24. ; xx.xx .even paction:.word null ,init ,copy ,fin .psect $code .sbttl Parse file_specification to get only filename.type ; input: (r5) address of source file_spec ; 2(r5) resultant string address ; output: r0 error code, if any ; ; internal register usage: ; r0 = action index ; r1 = current state ; r2 = input string pointer ; r4 --> resultant string namcvt::save mov @r5 ,r2 ; point to the input string mov 2(r5) ,r4 ; point to the output string clrb @r4 ; init output to be .asciz mov #1 ,r1 ; initialize current state tst rawfil ; /54/ really string stuff? beq 10$ ; /54/ yes strcpy r4 ,r2 ; /54/ no, copy as is clr r0 ; /54/ no errors br 100$ ; /54/ and exit 10$: tst r1 ; current state is zero? beq 80$ ; yes, exit then clr r3 ; get the next ch please bisb (r2)+ ,r3 ; simple bic #^c177 ,r3 ; ensure in range 0..127 dec r1 ; use previous state to get the mul #10 ,r1 ; index into the state table line movb chtype(r3),r0 ; /BBS/ column add r0 ,r1 ; add in the character class line+col movb ptable(r1),r1 ; and get the new state of system beq 80$ ; all done if new state is zero bmi 90$ ; error exit if < 0 clr r0 ; now mask off the action index from div #10. ,r0 ; the new state asl r0 ; word indexing to action routine jsr pc ,@paction(r0) ; simple br 10$ ; next please 80$: clr r0 ; no errors clrb @r4 ; .asciz for output br 100$ 90$: mov #-1 ,r0 ; error, bye 100$: unsave return .sbttl Action routines for the file name parser null: return init: mov 2(r5) ,r4 ; re-init the output string address clrb @r4 ; /BBS/ re-init the output buffer return copy: movb r3 ,(r4)+ ; copy a byte clrb @r4 ; terminate the string return ; next please fin: save ; all done, look for a dot mov 2(r5) ,r0 ; if there isn't any, add one tstb @r0 ; /BBS/ is there anything left? beq 30$ ; /BBS/ don't add a dot to nothing 10$: tstb @r0 ; end of the line yet? beq 20$ ; yes cmpb @r0 ,#'. ; a dot hanging around today? beq 30$ ; yes, exit inc r0 ; no, bump to next char br 10$ ; and try again please 20$: movb #'. ,r3 ; no dot, stuff one in please call copy ; simple 30$: unsave return .sbttl Check file extent to determine its type ; C H K E X T ; ; input: (r5) = file name ; output: r0 = if <>, assume it's a binary file chkext::save mov @r5 ,r1 ; /BBS/ save copy of pointer strlen r1 ; how much is left? tst r0 ; if nothing, then presume not binary beq 290$ ; nothing to do, exit add r0 ,r1 ; point to the end of the file name 210$: cmpb -(r1) ,#'. ; look for a dot which will delimit beq 220$ ; the file type sob r0 ,210$ ; not found, try again please br 290$ ; never found a dot (can't happen) 220$: copyz r1 ,#chkbuf,#5 ; /BBS/ make a copy so spaces aren't mov #chkbuf ,r1 ; /BBS/ written into actual name buff! strlen r1 ; # chars in file type, including "." mov #4 ,r3 ; /BBS/ flip operands for positive num sub r0 ,r3 ; /BBS/ must be 4 chars or less beq 225$ ; /BBS/ it's exactly 4, on to testing blt 290$ ; /BBS/ it's greater than 4, bail out mov r1 ,r2 ; /BBS/ save copy of pointer add r0 ,r2 ; /BBS/ point to last char 224$: movb #space ,(r2)+ ; /BBS/ space pad file extent sob r3 ,224$ ; /BBS/ until total length is 4 clrb @r2 ; /BBS/ null terminate padded string 225$: mov bintyp ,r2 ; ok, get listhead of file types 230$: mov r2 ,r3 ; get next file type address tstb @r3 ; end of the list? beq 290$ ; if null, then all done mov r1 ,r4 ; not done, get pointer to passed type call 310$ ; convert to upper case please cmpb r0 ,(r3)+ ; look for match on file type bne 240$ ; not today call 310$ ; convert to upper case please cmpb r0 ,(r3)+ ; again please bne 240$ ; not bloody likely call 310$ ; convert to upper case please cmpb r0 ,(r3)+ ; and so on bne 240$ ; you know call 310$ ; convert to upper case please cmpb r0 ,(r3)+ ; one more time beq 280$ ; a match, go say so.. 240$: add #4 ,r2 ; get the next one please br 230$ ; no match, try the next one 280$: mov #1 ,r0 ; flag it's a binary file br 300$ 290$: clr r0 ; not binary 300$: unsave return 310$: movb (r4)+ ,r0 ; get the next character and cmpb r0 ,#'A!40 ; convert to upper case blo 320$ ; no cmpb r0 ,#'Z!40 ; well? bhi 320$ ; not lower case bicb #40 ,r0 ; lower, convert to upper 320$: return .save .psect $rwdata ,rw,d,lcl,rel,con chkbuf: .byte 0 ,0 ,0 ,0 ,0 ,0 ; /BBS/ buffer for extents <3 chars .restore .sbttl File extents that are likely to be binary binini::strcpy bintyp ,#binl ; copy list below to buffer in high return ; memory so appending it is possible .save .psect $pdata .dsabl lc ; /BBS/ space-pad to four bytes if file type is less than four bytes.. binl: .ascii ".BAC" ; compiled BASIC files .ascii ".BAX" ; /BBS/ double precision .BAC files .ascii ".BIN" ; XXDP .ascii ".BOT" ; /BBS/ RT-11 boot files .ascii ".BUP" ; /62/ backup files .ascii ".CAL" ; /62/ spreadsheet files .ascii ".CRF" ; link cross reference files .ascii ".DEV" ; /BBS/ old logical disk file .ascii ".DSK" ; /BBS/ logical disk file .ascii ".EXE" ; executable image only, no data .ascii ".LDA" ; /62/ absolute load address images .ascii ".MLB" ; macro libraries .ascii ".OBJ" ; MACRO output files .ascii ".REL" ; /BBS/ RT-11 relocatable programs .ascii ".RTS" ; TSX+ run time systems .ascii ".SAV" ; RT-11 saved images .ascii ".SML" ; system macro libs .ascii ".STB" ; LINK symbol tables .ascii ".SYS" ; RT-11 monitors, drivers .ascii ".TSX" ; /BBS/ TSX+ system files .byte 0 ; /BBS/ end of it all .even .enabl lc ; /BBS/ restore this too .restore .sbttl Convert invalid characters to something reasonable ; F I X F I L E ; ; Input: (r5) = source string, .asciz ; 2(r5) = destination string, .asciz ; Output: r0 = zero if unmodified, else non-zero (for warnings) ; ; The main reason for this is to protect ourselves against the ; file naming conventions used for TOPS20 and VMS so we do not ; die on a bad file name. .save .psect $pdata defchr: .byte 'X&137 ; replace any bad char with this .even .restore fixfil::save mov @r5 ,r1 ; source string mov 2(r5) ,r2 ; destination string clr r3 ; assume no mods made to file name 10$: tstb @r1 ; end of the source file name? beq 35$ ; yes, exit scan @r1 ,#okchr ; check for invalid characters tst r0 ; did we find one yet bne 20$ ; no (we checked for legit chars) mov #er$fnm ,r3 ; /BBS/ flag we found a bad character movb defchr ,@r2 ; and insert the fixup character br 30$ ; next.. 20$: movb @r1 ,@r2 ; character is ok, stuff it in 30$: inc r1 ; advance to next src char inc r2 ; advance to next dst char br 10$ ; next char in file name please ; /51/ following added for RT-11 35$: clrb @r2 ; .asciz /BBS/ got to do this here sub #256. ,sp ; /62/ allocate a buffer mov sp ,r1 ; and get a temporary copy mov 2(r5) ,r2 ; the destination string copyz r2 ,r1 ,#255. ; /62/ copy the formatted string scan #': ,r1 ; /BBS/ look for a device delimiter tst r0 ; /BBS/ find one? beq 37$ ; /BBS/ no.. 36$: movb (r1)+ ,(r2)+ ; /BBS/ ya, copy dev name before test sob r0, 36$ 37$: mov #6 ,r0 ; setup to truncate file name 40$: cmpb (r1) ,#'. ; end of file name field? beq 70$ ; yes, skip to file type copy movb (r1)+ ,(r2)+ ; copy the character beq 90$ ; and exit on a null sob r0 ,40$ ; next please 60$: tstb (r1) ; loop for looking for null or a dot.. beq 90$ ; null, end of string then cmpb (r1) ,#'. ; we may have truncated the name beq 70$ ; so look for a dot for the file type mov #er$fnm ,r3 ; /BBS/ and flag that we altered name inc r1 ; next please br 60$ ; go to it 70$: mov #4 ,r0 ; at most 3 chars + "." in file type 80$: movb (r1)+ ,(r2)+ ; finish off with the file type beq 90$ ; /BBS/ don't copy crud after null sob r0 ,80$ ; next please tstb (r1) ; /62/ anything left over? beq 90$ ; /62/ nope.. mov #er$fnm ,r3 ; /62/ ya, flag type was truncated.. 90$: clrb (r2) ; ensure .asciz /BBS/ no need to (r2)+ add #256. ,sp ; end of RT-11 file name truncation mov r3 ,r0 ; return status unsave return .save .psect $pdata okchr: .ascii "0123456789.:" ; /BBS/ allow device in file spec .ascii "abcdefghijklmnopqrstuvwxyz" .ascii "ABCDEFGHIJKLMNOPQRSTUVWXYZ" .byte 0 .even .restore .sbttl Convert strings ala abcde<15> or abcde\015 to binary format prsarg::save ; /45/ save regs mov argbuf ,r3 ; /41/ argbuf address mov r0 ,r4 ; /41/ where to return parsed string 10$: movb (r3)+ ,r2 ; /41/ while (*argbuf) beq 100$ ; /41/ exit with success cmpb r2 ,#'\ ; /45/ "C" style notation? beq 50$ ; /45/ yes cmpb r2 ,#'< ; /41/ start of an octal sequence? bne 40$ ; /41/ no clr r1 ; /41/ init accumulator 20$: movb (r3)+ ,r2 ; /41/ while (*argbuf++) beq 90$ ; /41/ error, no terminator cmpb r2 ,#'> ; /41/ octal number terminator? beq 30$ ; /41/ yes, exit loop cmpb r2 ,#'0 ; /41/ check for legitimate value blo 90$ ; /41/ not an octal digit, error cmpb r2 ,#'7 ; /41/ check again please bhi 90$ ; /41/ not legit, error sub #'0 ,r2 ; /41/ yes, convert to octal until ">" ash #3 ,r1 ; /62/ shift left 3 bits add r2 ,r1 ; /41/ add in current digit br 20$ ; /41/ no 30$: mov r1 ,r2 ; /41/ yes, get set to insert value 40$: movb r2 ,(r4)+ ; /41/ place current char or value in br 10$ ; /41/ next please 50$: clr r1 ; /45/ "C" style notation clr -(sp) ; /45/ trip counter 60$: movb (r3) ,r2 ; /45/ copy a character beq 70$ ; /45/ EOS, exit next time cmpb r2 ,#'0 ; /45/ octal characters? blo 70$ ; /45/ no, exit this loop cmpb r2 ,#'7 ; /45/ ... bhi 70$ ; /45/ copy the character inc (sp) ; /45/ been here at least once sub #'0 ,r2 ; /45/ yes, convert to octal ash #3 ,r1 ; /62/ shift left 3 bits add r2 ,r1 ; /45/ add in current digit inc r3 ; /45/ next please br 60$ ; /45/ do it 70$: tst (sp)+ ; /45/ did we really get a number? beq 75$ ; /45/ no, ignore then movb r1 ,(r4)+ ; /45/ done, copy the data br 80$ ; /45/ and get next please 75$: tstb r2 ; /45/ no number, perhaps "\\" or beq 80$ ; /45/ or "\<" was present? movb r2 ,(r4)+ ; /45/ must have had "\x" inc r3 ; /45/ point to next char please 80$: br 10$ ; /45/ go get it 90$: mov #-1 ,r0 ; /41/ failed br 110$ ; /41/ exit 100$: clr r0 ; /41/ success 110$: clrb @r4 ; /41/ ensure string is .asciz unsave ; /45/ unsave regs return .sbttl Unformat a string, inverse of PRSARG .save .psect $rwdata ,rw,d,lcl,rel,con ubuf: .blkb 80. ; the output buffer .restore unfmts::save mov r0 ,r5 ; copy the address of the data mov #ubuf ,r4 ; target buffer 10$: movb (r5)+ ,r1 ; get the data beq 100$ ; all done cmpb r1 ,#space ; control character? blo 20$ ; yes movb r1 ,(r4)+ ; no, just copy as is br 40$ ; and do the next one 20$: movb #'\ ,(r4)+ ; control character, insert "\" clr r0 ; get setup for conversion div #10 ,r0 ; got it movb r1 ,r2 ; save the LSB mov r0 ,r1 ; and get the last two out clr r0 ; .... div #10 ,r0 ; do it add #'0 ,r0 ; convert to ascii add #'0 ,r1 ; ..ditto add #'0 ,r2 ; ....ditto movb r0 ,(r4)+ ; insert movb r1 ,(r4)+ ; the movb r2 ,(r4)+ ; data 40$: br 10$ ; next please 100$: clrb @r4 ; ensure .asciz mov #ubuf ,r0 ; return address of converted data unsave return .end