.TITLE CSI .IDENT /V1.1/ .ENABL LC ; ; CSI -- SUBROUTINES TO PROVIDE FORTRAN ACCESS TO THE SYSTEM ; COMMAND STRING INTERPRETER ROUTINES ; ;+ ; ; CALL CSI1 (BUFFER [,LENGTH] [,NEWLEN] [,IEFLG] [,IESIZ] ) ; INITIALIZE CSI CONTROL BLOCK AND PRE-SCAN COMMAND STRING ;WHERE: ; BUFFER - COMMAND-LINE TO BE PROCESSED (USUALLY RETURNED ; FROM GETCMD) ; LENGTH - LENGTH OF COMMAND-LINE (ALSO FROM GETCMD) ; IF NOT PRESENT, FIRST NULL CHAR TERMINATES LINE ; NEWLEN - RETURNED LENGTH OF COMPRESSED COMMAND-LINE ; IT IS LEGAL TO SPECIFY THE SAME VARIABLE FOR ; BOTH LENGTH AND NEWLEN ; *** IF ZERO, ERROR DURING COMPRESSION ; IEFLG - ERROR/EQUAL FLAG; VALUES ARE: ; 0 : NO ERROR....EQUAL SIGN PRESENT IN COMMAND ; -1 : NO ERROR....NO EQUAL SIGN IN COMMAND ; >0 : INDEX INTO BUFFER WHERE ERROR STARTS ; IESIZ - IF AN ERROR HAS BEEN DETECTED, LENGTH OF SEGMENT ; CONTAINING THE ERROR ;- .MCALL CSI$,CSI$1,CSI$2,NMBLK$ CSI$ ;DEFINE AND ALLOCATE CSI CONTROL BLOCK C.DVFI = 30 ;OFFSET TO DEFAULT INPUT DEVICE SPEC C.DVFO = 34 ;OFFSET TO DEFAULT OUTPUT DEVICE SPEC C.DIFI = 40 ;OFFSET TO DEFAULT INPUT DIRECTORY SPEC C.DIFO = 44 ;OFFSET TO DEFAULT OUTPUT DIRECTORY SPEC C.DFOF = C.DIFO-C.DIFI ;OFFSET FROM INPUT TO OUTPUT DEFAULTS C.DFVI = C.DIFI-C.DVFI ;OFFSET FROM DEVICE TO DIRECTORY DEFAULTS CSIBLK: .BLKB C.SIZE .EVEN INMBLK: NMBLK$ ;ALLOCATE A DEFAULT INPUT NAME BLOCK ONMBLK: NMBLK$ ;ALLOCATE A DEFAULT OUTPUT NAME BLOCK NB.DOT = 100000 ;FCS FLAG BIT NB.SMI = 40000 ;FCS FLAG BIT ; ; DEFINE FORTRAN FILESPEC STRING OFFSETS DEV = 0 ;DEVICE NAME: DD##: UFD = 5 ;UFD SPEC: [###,###] FNM = 14. ;FILENAME: ABCDEFGHI EXT = 23. ;EXTENSION: .EXT VER = 27. ;VERSION: ;##### ;-1 NUL = 33. ;ASCIZ TERMINATOR SPACE = 40 COMMA = 54 MFSUBR CSI1 ;DEFINE ENTRY AND LINK MFARG 5,1 ; 5 ARGS, 1ST REQUIRED MOV #INMBLK,R0 ;FIRST, ZERO DEFAULT NAME BLOCK MOV #ONMBLK,R2 ;BOTH OF THEM MOV #S.FNB/2,R1 ; GET SIZE 1$: CLR (R0)+ CLR (R2)+ SOB R1,1$ POP R5 ;GET BUFFER ARG POP R4 ;LENGTH SPECIFIED? BNE 10$ ; YES MOV R5,R4 ; NO, COPY BUFFER ADDRESS 5$: TSTB (R4)+ ;SEARCH FOR NULL BNE 5$ DEC R4 ;BACK OFF ONE SUB R5,R4 ;COMPUTE BYTE COUNT BR 15$ 10$: MOV (R4),R4 ;GET SIZE 15$: CLR R1 ;CLEAR ERROR FLAG CLR R2 CSI$1 #CSIBLK,R5,R4 ;INITIALIZE AND PRESCAN COMMAND-LINE MOV C.CMLD(R0),R4 ;GET NEW LENGTH OF COMPRESSED LINE BCC 20$ ; NO ERROR IN CSI$1 MOV C.FILD(R0),R2 ;GET LENGTH OF ERROR MOV C.FILD+2(R0),R1 ;GET ADDR OF ERROR SUB R5,R1 ;GET BYTE OFFSET TO ERROR INC R1 ;GET ARRAY INDEX TO ERROR 20$: POP R3 ;GET ADDR OF NEWLEN BEQ 25$ ; OMITTED MOV R4,(R3) ;RETURN LENGTH OF COMPRESSED LINE 25$: POP R3 ;GET ADDR OF IEFLG BEQ 30$ ; OMITTED MOV R1,(R3) ;SET ERROR INDEX BNE 30$ ;ERROR HAD OCCURRED BITB #CS.EQU,C.STAT(R0) ;EQUAL SIGN SEEN? BNE 30$ ; YES, LEAVE FLAG AT ZERO DEC (R3) ; NO, SET FLAG TO -1 30$: POP R3 ;GET ADDR OF IESIZ BEQ 40$ ; OMITTED MOV R2,(R3) ;SET ERROR SIZE 40$: RETURN ;+ ; CALL CSIDEF ( IO [,DEVICE] [,UFD] [,NAME] [,EXT] [,VER] ) ; ESTABLISH DEFAULT FIELDS FOR CSI2 PARSING ;WHERE: ; IO - ASCII CHAR INDICATING INPUT/OUTPUT DEFAULT FILESPEC: ; 'I' -> THIS DEFAULT APPLIES TO INPUT FILES ; 'O' -> THIS DEFAULT APPLIES TO OUTPUT FILES ; DEVICE - ASCII DEVICE NAME OF THE FORM: ; DD##: or DD#: or DD: ; UFD - ASCII DIRECTORY SPECIFICATION OF THE FORM: ; [###,###] where ### may be 1-3 digits ; NAME - ASCII FILENAME STRING (IF NON-ZERO, THIS ARG ; MUST BE 9 CHARACTERS LONG) ; EXT - ASCII FILE EXTENSION (IF NON-ZERO, THIS ARG ; MUST BE 3 CHARACTERS LONG) ; VER - ASCII VERSION NUMBER STRING (OCTAL NUMBER) ;NOTES: ; 1) If any parameters are omitted, the corresponding field from the ; previous parsed filespec will remain as the default, with the ; exception of VER, which reverts to zero (latest version). Note that ; CSI1 clears all defaults automatically. ; 2) If any parameters are explicitly zero, the corresponding default ; field will be cleared to indicate that no default exists. ; 3) All strings must be left justified. NAME and EXT require spaces ; filling out to the end of the field. ; 4) The version number of a filespec is normally an OCTAL number from ; 1 to 77777 (32767.); the two special version numbers ( 0 and -1 ) ; have their normal meaning (i.e., zero denotes the most recent ; version of an existing file or the next incremental version of a ; file to be created; minus one denotes the oldest version of a file). ; 5) Version number strings in VER must have a non-numeric terminator. ; A space is sufficient. Note that '-1' and '7' have indeterminate ; results where '-1 ' and '7 ' are valid. ; 6) The string in EXT should not be preceeded by a period. The string ; in VER should not be preceedded by a semi-colon. However, the ; string in UFD must include both square brackets and comma; the ; string in DEVICE must include the trailing colon. ;- MFSUBR CSIDEF ; Set up FORTRAN entry and link MFARG 6,1 ; 1st arg required CLR R1 ; Assume INPUT default MOVB @(SP)+,R0 ; Get IO CMPB R0,#'I ; Is that right? BEQ 3$ ; Yes CMPB R0,#'O ; No....OUTPUT default? BNE 999$ ; No....ERROR MOV #C.DFOF,R1 ; Yes...get offset to output defaults 3$: MOV R1,R2 ; Save IO flag ADD #CSIBLK+C.DVFI,R1 ; Point to DSD for default parse MOV #2,R0 ; Keep ctr (DEVICE and UFD are treated the same) 5$: POP R5 ; Got a DEVICE/UFD ? BEQ 25$ ; No....leave old default MOV R5,R4 ; Yes...make sure it is non-blank CLR (R1) ; Count the characters 10$: MOVB (R4)+,R3 ; Get the next char CMPB R3,#SPACE ; Printable ASCII? BLE 15$ ; No....done INC (R1) ; Yes...count it and loop BR 10$ 15$: TST (R1)+ ; Skip count in DSD MOV R5,(R1)+ ; Set string address in DSD BR 30$ 25$: ADD #4,R1 ; No parameter supplied...skip this DSD entry 30$: ADD #C.DFVI-4,R1 ; Skip to next default spec SOB R0,5$ ; Loop for 1st two arguments MOV #INMBLK+N.FNAM,R5 ; Assume INPUT TST R2 ; Correct? BEQ 32$ ; Yes MOV #ONMBLK+N.FNAM,R5 ; No....set OUTPUT default fnb 32$: POP R0 ; NAME supplied? BEQ 50$ ; No MOV #3,R4 ; Filename becomes 3 RAD50 words TSTB (R0) ; Default allowed? BNE 40$ ; Yes...NAME is the default 35$: CLR (R5)+ ; No....clear old default SOB R4,35$ BR 55$ 40$: CLR R1 ; Flag to disallow period CALL $CAT5B ; Convert ASCII including blanks BCS 999$ ; ERROR...bad string MOV R1,(R5)+ ; Set the RAD50 word in default FNB SOB R4,40$ ; Loop for whole filename BR 55$ 50$: ADD #6,R5 ; Skip filename portion of FNB 55$: POP R0 ; Got an EXT ? BEQ 75$ ; No TSTB (R0) ; Default allowed? BNE 60$ ; Yes...that's it CLR (R5) ; No....clear the old one BR 75$ 60$: CLR R1 ; No period allowed CALL $CAT5B ; Convert to RAD50 BCS 999$ ; ERROR...bad string MOV R1,(R5) ; Move in converted extension 75$: TST (R5)+ ; Point to version number CLR R1 ; Set default to zero POP R0 ; Get version number default string BEQ 90$ ; None....zero it TSTB (R0) ; Default supplied? BEQ 90$ ; No....zero it CALL $COTB ; Yes...convert octal to binary 90$: MOV R1,(R5) ; Set version number RETURN 999$: TEVARG ; BAD ARGUMENT VALUE (IO or NAME or EXT) ;+ ; CALL CSIFIL (INFIL, OUTFIL [,NEWSIZ] ) ; COMPRESS THE GARBAGE OUT OF A FILESPEC (SPACES, VERSION ZEROES) ;WHERE: ; INFIL - LOGICAL*1 (34) ARRAY RETURNED FROM CSI2 ; OUTFIL - LOGICAL*1 (34) ARRAY RETURNED FROM CSIFIL ; NEWSIZ - INTEGER NUMBER OF VALID CHARACTERS RETURNED ;NOTES: ; 1) IF YOU INSIST ON USING CALL ASSIGN RATHER THAN THE OPEN STATEMENT, ; YOU MUST SPECIFY A COMPRESSED STRING WITH THE RETURNED NEWSIZ, ; E.G.: CALL ASSIGN (LUN,OUTFIL,NEWSIZ) ; HOWEVER, THE OPEN STATEMENT ACCEPTS THE UNCOMPRESSED STRING. ; ;- MFSUBR CSIFIL ;DECLARE FORTRAN ENTRY MFARG 3,<1,2> ;1ST TWO ARGS REQUIRED POP R1 ;GET INFIL POP R0 ;GET OUTFIL CLR R2 ;CLEAR CHARACTER COUNTER 5$: MOVB (R1)+,R5 ;GET A CHARACTER BEQ 25$ ; NULL....DONE CMPB R5,#SPACE ; BLANK? BEQ 5$ ; YES...SKIP IT CMPB R5,#'; ; NO....SEMI-COLON? BEQ 10$ ; YES...CHECK VERSION NUMBER 8$: MOVB R5,(R0)+ ; NO....TRANSFER CHARACTER INC R2 ;COUNT IT BR 5$ ;AND GET THE NEXT ONE 10$: MOVB (R1)+,R4 ;GET NEXT NUMBER IN VERSION NUMBER BEQ 25$ ; DONE CMPB R4,#'0 ; ZERO? BEQ 10$ ; YES...SKIP IT MOVB R5,(R0)+ ; NO....PUT SEMI-COLON IN OUTPUT INC R2 ; AND COUNT IT MOVB R4,R5 ; PUT 1ST NON-ZERO CHAR IN R5 BR 8$ ; AND CONTINUE SHUFFLING STRING 25$: CLRB (R0) ;CLEAR OUT LAST CHAR POP R1 ;GET NEWSIZ BEQ 30$ ; NONE MOV R2,(R1) ;PUT IN COUNT OF VALID CHARACTERS 30$: RETURN ;+ ; CALL CSI2 (IO, OUTFIL [,LSTAT] [,SWTAB] [,MASK1] [,MASK2] ) ; PARSE A FILESPEC WITH OPTIONAL SWITCHES AND DEFAULTS ;WHERE: ; IO - ASCII CHAR INDICATING INPUT/OUTPUT FILESPEC: ; 'I' -> PARSE THE NEXT INPUT FILESPEC ; 'O' -> PARSE THE NEXT OUTPUT FILESPEC ; OUTFIL - 34 BYTE ARRAY TO RECEIVE THE PARSED FILESPEC. ; IF CSI2 RETURNS AN ERROR, OUTFIL(1) = 0 (NULL). ; THIS ARRAY WILL CONTAIN AN ASCIZ STRING WITH ; FILESPEC INFORMATION AS FOLLOWS: ; OUTFIL ( 1 - 5 ) DEVICE NAME { DD##: } ; OUTFIL ( 6 - 14) UFD SPEC { [###,###] } ; OUTFIL (15 - 23) FILE NAME { ABCDEFGHI } ; OUTFIL (24 - 27) EXTENSION { .XYZ } ; OUTFIL (28 - 33) VERSION { ;##### } ; OUTFIL (34) NULL ASCIZ TERMINATOR ; INDIVIDUAL FIELDS WILL BE LEFT-JUSTIFIED AND ; PADDED WITH SPACES. THE SYNTACTICAL REQUIREMENTS ; (E.G., " :[,].; ") WILL ALWAYS BE AT FIXED OFFSETS. ; LSTAT - RETURNED STATUS BYTE (DECLARE AS FORTRAN INTEGER ; IF YOU WANT TO DO BITWISE LOGICAL TESTS ON IT) ; SWTAB - SWITCH DESCRIPTOR TABLE ; MASK1 - RESULTANT SWITCH MASK WORD ; MASK2 - RESULTANT POLARITY MASK WORD ; ;NOTES: ; 1) Defaults may be established in all filespec fields by calling ; CSIDEF before calling CSI2. Note that each call to CSI2 updates ; all defaults (excluding version number!) to match the current ; filespec. This means that input and output device, ufd, file ; name, and file extension specifications will propagate across ; commas. CSIDEF will alter this default propagation. If you ; want version numbers to propagate, you must call CSIDEF with ; the VER argument pointing to the preceding CSI2 version number ; string (OUTFIL(29)). ;- MFSUBR CSI2 ;DECLARE ENTRY MFARG 6,<1,2> ;1ST 2 ARGS REQUIRED MOVB #CS.INP,R5 ; Assume INPUT filespec request MOVB @(SP)+,R0 ; Get IO arg value CMPB R0,#'I ; INPUT ? BEQ 5$ ; Yes CMPB R0,#'O ; OUTPUT ? BEQ 1$ ; Yes 999$: TEVARG ; No....BAD ARG VALUE 1$: MOVB #CS.OUT,R5 ; OUTPUT CSI2 request 5$: MOVB R5,CSIBLK+C.TYPR ; Set switch value in control block POP R5 ; Get address of OUTFIL POP R3 ; Get address of LSTAT BNE 30$ ; got it MOV #CSIBLK+C.STAT,R3 ; LSTAT not supplied...set a dummy 30$: POP CSIBLK+C.SWAD ; Set address of SWTAB in control block CSI$2 #CSIBLK ; DO THE FILESPEC DECODING BCC 50$ ; No error 800$: ADD #4,SP ; ERROR....skip everything else CLRB (R5) ; OUTFIL(1) = 0 RETURN 50$: ; No error: the fun's just beginning! POP R0 ; Any MASK1 ? BEQ 55$ ; No MOV CSIBLK+C.MKW1,(R0) ; Yes, set it 55$: POP R0 ; Any MASK2 ? BEQ 60$ ; No MOV CSIBLK+C.MKW2,(R0) ; Yes, set it up 60$: MOVB CSIBLK+C.STAT,(R3) ; Return status to LSTAT (or noplace) MOV CSIBLK+C.DEVD+2,R0 ; Set address of ASCII device name TST CSIBLK+C.DEVD ; Got a residual device name? BNE 75$ ; Yes...put it in OUTFIL MOV #5,R0 ; Can't find any device name....set length 70$: MOVB #SPACE,(R5)+ ; and clear out device spec in OUTFIL SOB R0,70$ BR 80$ ; Go try for UFD 75$: MOVB (R0)+,(R5)+ ; Move 1st two letters (device name) MOVB (R0)+,(R5)+ ; into OUTFIL CALL $COTB ; Convert unit number to binary MOV R5,R0 ; Copy OUTFIL string address CBTAR2 2,O,U,ZERO ; Set to convert back to 2-digit octal CALL $CBTA ; MOVB #':,(R0)+ ; Set terminator MOV R0,R5 ; Update ptr 80$: MOV CSIBLK+C.DIRD+2,R0 ; Set address of UFD spec TST CSIBLK+C.DIRD ; Any default? BNE 95$ ; Yes...move it into OUTFIL MOV #9.,R0 ; Can't find any UFD so clear spec in OUTFIL 90$: MOVB #SPACE,(R5)+ ; SOB R0,90$ ; BR 100$ ; Now try for a filename 95$: INC R0 ; Skip the '[' in the UFD spec CALL $COTB ; Convert group code from Octal PUSH R1 ; and save it on the stack CALL $COTB ; Convert member code MOV (SP),R2 ; Retrieve group code MOV R1,(SP) ; Save member MOV R2,R1 ; Retrieve group MOV R5,R0 ; Set dest string address (OUTFIL) MOVB #'[,(R0)+ ; Set initial char CBTAR2 3,O,U,ZERO ; Set to convert to 3-digit Octal CALL $CBTA ; MOVB #COMMA,(R0)+ ; Set separator POP R1 ; Get member CBTAR2 3,O,U,ZERO ; CALL $CBTA ; Convert into OUTFIL MOVB #'],(R0)+ ; Set delimeter MOV R0,R5 ; and restore string pointer 100$: CLR R2 ; Assume no filename BITB #CS.NMF,(R3) ; Did CSI2 return one? BEQ 105$ ; No MOV #CSIBLK+C.DSDS,R2 ; Yes...set DSD ptr 105$: MOV #INMBLK,R3 ; Set address of default INPUT FNB CMPB #CS.INP,CSIBLK+C.TYPR ; Input request? BEQ 110$ ; Yes MOV #ONMBLK,R3 ; No....set OUTPUT FNB 110$: MOV R3,R1 ; Set destination filename block CLR N.STAT(R1) ; Clear leftover bits MOV #INMBLK-F.ERR,R0 ; Set phony FDB address CALL .PRSFN ; Parse filename (writes F.ERR(R0)) MOV R1,R3 ; Copy resultant FNB address ADD #N.FNAM,R3 ; Point to parsed filename MOV R5,R0 ; Copy OUTFIL ptr MOV (R3)+,R1 ; Get 1st 3rd of name CALL $C5TA ; and turn it to ASCII MOV (R3)+,R1 ; Get 2nd 3rd CALL $C5TA MOV (R3)+,R1 ; Get 3rd 3rd CALL $C5TA MOVB #'.,(R0)+ ; Set extension dot MOV (R3)+,R1 ; Get parsed RAD-50 extension CALL $C5TA ; Turn to ASCII MOVB #';,(R0)+ ; Put in version number delimiter MOV (R3),R1 ; Get parsed (binary) version number BPL 200$ ; Not -1 MOVB #'-,(R0)+ ; Yes...move in special string: '-1 ' MOVB #'1,(R0)+ MOVB #SPACE,(R0)+ MOVB #SPACE,(R0)+ MOVB #SPACE,(R0)+ BR 225$ 200$: CBTAR2 5,O,U,ZERO ; Turn version number into 5-digit octal CALL $CBTA 225$: CLR (R3) ; clear version number default CLRB (R0) ; set ASCIZ null terminator RETURN ; All done (at last) .END