.OPVER=0 ;assemble code for OPRESET ; .OPVER=1 ;assemble code for OPTEST ; .OPVER=2 ;assemble code for OPSET IFE .OPVER,> IFE .OPVER-1,<TITLE OPTEST Tests a SETUP option flag IF1 <PRINTX Assembling OPTEST code>> IFE .OPVER-2,<TITLE OPSET Sets a SETUP option flag IF1 <PRINTX Assembling OPSET code>> SEARCH MONSYM,MACSYM Comment ^ Revision History [1] R. Swick 30-Oct-79. Initial release. ^ MAXCHR==^D500 ;MAXIMUM # OF CHAR IN MCF LINE PDLEN==100 ;SIZE OF STACK .WRDCNT==0 ;#words used in SETUP.BIN .VARST==1 ;start of linked list for variables .OPTST==2 ;start of linked list for options .EMPST==3 ;start of linked list for empty blocks WAITIM==^D10 ;milliseconds between waits for access MAXTRY==^D200 ;max # of trys to get access to list BINMAX==2 ;max # of pages in SETUP.BIN SALL F==0 ;flags F%VAC==1B3 ;access granted to variable list in SETUP.BIN F%OAC==1B4 ;access granted to option list in SETUP.BIN F%EAC==1B5 ;access granted to empty block list in SETUP.BIN .AC4=4 ;another temporary accumulator T1==5 P1==10 ;ACCUMULATORS USED MAINLY TO HOLD BYTE pointer CH==15 ;HOLDS A CHARACTER DEFINE PARSE(typ,flgs,data,hlpm,def,lst)< MOVEI .AC1,CMBLOK MOVEI .AC2,[FLDDB. <typ>,<flgs>,<data>,<hlpm>,<def>,<lst>] COMND TDNE .AC1,[CM%NOP]> DEFINE ITEM(text,addr)< XWD [ASCIZ /text/],addr> DEFSTR (VALLEN,,^D5,^D6) ;data structure for # words in value DEFSTR (VALLOC,,^D17,^D12) ;data structure for addr of value DEFSTR (FWDPTR,,^D35,^D18) ;data structure for linked list pntr SUBTTL ***MAIN PROGRAM*** START: MOVE P,[XWD PDLEN,PDLIST] ;initialize stack MOVE .AC1,[XWD .PRIIN,.PRIOU] MOVEM .AC1,CMBLOK+.CMIOJ ;setup COMND jfns HRROI .AC1,[0] ;no prompt for now MOVEM .AC1,CMBLOK+.CMRTY HRROI .AC1,LINE MOVEM .AC1,CMBLOK+.CMBFP ;COMND buffer pointer MOVEM .AC1,CMBLOK+.CMPTR ;next input to be parsed MOVEI .AC1,MAXCHR MOVEM .AC1,CMBLOK+.CMCNT ;size of input buffer SETZM BINJFN ;reset jfn of default file SETZ .AC1, ;make EXEC command line available RSCAN% NOP SETZ F, ;clear all flags PARSE .CMINI ;initialize COMND JFCL REPARS: PARSE .CMFLD ;parse the command name JRST INIERR ;couldn't parse this MOVE P1,[POINT 7,ANSW1] ;assemble name here SETZM ATMBUF ;initialize in case of un-parseable name CALL PRSOPT ;parse an option name, leave it in ANSW1 JRST INVNAM ;invalid option name PARSE .CMCFM ;confirm it JRST INICFM ;not confirmed MOVE .AC1,[-1,,.OPTST] ;get write access to option list CALL ACCESS SETZM SVALUE ;default option value to NO MOVEI .AC1,.OPTST ;get option list pointer MOVE .AC2,[POINT 7,ANSW1] ;find this name in list MOVEI .AC3,BINDEF ;start here CALL SRCHLL ;find name in list IFE .OPVER,< SKIPA ;skip if not already there CALL SELSAV ;set value to NO TMSG ([) HRROI .AC1,ANSW1 PSOUT% TMSG ( reset])> IFE .OPVER-1,< SKIPA ;skip if not already there JRST [MOVE .AC1,LSTPTR ;else get list pointer LOAD .AC1,VALLOC,BINDEF(.AC1) ;and get value SKIPN .AC1 ;skip if set JRST .+1 ;else say not set TMSG (?) HRROI .AC1,ANSW1 PSOUT% TMSG ( is set) JRST QUIT] TMSG ([) HRROI .AC1,ANSW1 PSOUT% TMSG ( is not set])> IFE .OPVER-2,< CALL SELSAV ;not there, so save it now MOVE .AC1,LSTPTR LOAD .AC1,VALLOC,BINDEF(.AC1) ;get option value SKIPE .AC1 ;must be NO JRST [TMSG (?) ;or say flag is already set HRROI .AC1,ANSW1 PSOUT% TMSG ( is already set) JRST QUIT] ;and quit SETOM SVALUE ;else set the option to be YES CALL SELSAV ;store the new value TMSG ([) ;type out a message HRROI .AC1,ANSW1 PSOUT% TMSG ( set])> QUIT: CALL CLRACS ;clear any access to option list SKIPE BINJFN ;skip if default file not mapped CALL RELBIN ;release SETUP.BIN HALTF% ;quit JRST .-1 ;if continued SUBTTL Save an option value in SETUP.BIN ; Called to save an option in SETUP.BIN ; ; Returns +1 always SELSAV: MOVEI .AC1,.OPTST MOVE .AC2,[POINT 7,ANSW1] ;search for option in list MOVEI .AC3,BINDEF CALL SRCHLL SKIPA ;not found, then store name JRST SELSV2 MOVE .AC1,[-1,,.EMPST] ;get access to empty-block list CALL ACCESS MOVE .AC1,[POINT 7,ANSW1] ;byte pointer to option name SETZ .AC2, ;count of bytes in name ILDB .AC3,.AC1 ;get a char SKIPE .AC3 ;found end of name? AOJA .AC2,.-2 ;nope, then loop again ADDI .AC2,5 ;round up+nul IDIVI .AC2,5 ;get # words needed AOS .AC2 ;plus one for header MOVEI .AC1,.EMPST ;start of empty-block list CALL SRCHMT ;find a place for name MOVEM .AC1,.AC3 ;save address ADDI .AC1,BINDEF ;make it absolute ADD .AC2,.AC1 ;addr of last word to move AOJ .AC1, ;leave room for header HRLI .AC1,ANSW1 ;move option name to there BLT .AC1,(.AC2) MOVE .AC1,LSTPTR ;addr of preceeding item LOAD .AC2,FWDPTR,BINDEF(.AC1) ;get old fwd ptr STOR .AC3,FWDPTR,BINDEF(.AC1) ;new one is this addr STOR .AC2,FWDPTR,BINDEF(.AC3) ;this one points to next MOVEM .AC3,LSTPTR ;save new list pointer to option SELSV2: MOVE .AC3,LSTPTR ;addr of item in list MOVE .AC4,SVALUE ;value of option STOR .AC4,VALLOC,BINDEF(.AC3) ;store it RET ; Parse an option name since options may look like "(foo)" or "<foo>" ; Accepts: P1 is a byte pointer to a place to put the parsed name ; ; Return+1: No valid option name ; Return+2: Option name is in place pointed to by P1 PRSOPT: PARSE .CMFLD,CM%SDH,,<name> RET ;invalid name SKIPN ATMBUF ;saw a name? JRST [ILDB CH,CMBLOK+.CMPTR ;get the char COMND wasn't able to parse CAIN CH,15 ;end of line? RET ;yep, then return+1 CAIN CH,12 RET IDPB CH,P1 ;put it into ANSW1 SOS CMBLOK+.CMINC ;decrement COMND state block for monitor JRST PRSOPT] MOVE .AC1,P1 HRROI .AC2,ATMBUF SETZB .AC3,.AC4 SOUT ;move option name to ANSW1 PRSOP1: SKIPN CMBLOK+.CMINC ;any more characters input? JRST PRSOP2 ;nope ILDB CH,CMBLOK+.CMPTR ;get char that terminated COMND CAIN CH," " ;terminated by space JRST PRSOP2 CAIN CH,15 ;or end of line? JRST PRSOP2 CAIN CH,12 JRST PRSOP2 CAIE CH,11 ;or tab? JRST [IDPB CH,.AC1 ;nope, then a part of the name SOS CMBLOK+.CMINC ;one less char for COMND to parse JRST PRSOP1] ;look some more PRSOP2: SETZ CH, ;make name ASCIZ IDPB CH,.AC1 MOVNI .AC1,1 ADJBP .AC1,CMBLOK+.CMPTR ;backup COMND pointer MOVEM .AC1,CMBLOK+.CMPTR AOS (P) ;give skip-return RET SUBTTL Linked-list search routine ; Accepts: AC1 = address of start of list ; AC2 = byte pointer to ASCIZ item to be found ; AC3 = base address of list to which all pointers are relative ; ; Returns: +1 Item not found: LSTPTR = address of item preceeding this one in list ; ; +2 Item found: LSTPTR = adress of item in list SRCHLL: PUSH P,.AC1 ;save current list pointer ADD .AC1,.AC3 ;make pointer absolute LOAD .AC1,FWDPTR,(.AC1) ;get forward pointer SKIPG .AC1 ;end of list reached yet? JRST SRCHL3 ;yep MOVE T1,.AC1 ;get new pointer ADD T1,.AC3 ;make forward pointer absolute HLL T1,[POINT 7,0,35] ;make it a byte pointer to item MOVEM T1,LSTPTR ;save it MOVEM .AC2,ITMPTR ;save byte pointer to search value SRCHL1: ILDB T1,LSTPTR ;get a char of the list item ILDB CH,ITMPTR ;and one from the value SKIPN CH ;end of value? JRST SRCHL2 ;yep CAMN T1,CH ;equal so far? JRST SRCHL1 ;yep CAIL T1,"a" ;raise lowercase to uppercase if possible CAILE T1,"z" SKIPA SUBI T1,"a"-"A" CAIL CH,"a" ;here too CAILE CH,"z" SKIPA SUBI CH,"a"-"A" CAMN T1,CH ;equal now? JRST SRCHL1 ;yep CAML T1,CH ;list item still less? JRST SRCHL3 ;nope POP P,LSTPTR ;discard prior pointer JRST SRCHLL ;and try next item SRCHL2: SKIPN T1 ;end of list item reached also? JRST [POP P,LSTPTR ;discard old forward pointer JRST SRCHL4] SRCHL3: POP P,LSTPTR ;restore old forward pointer RET SRCHL4: MOVEM .AC1,LSTPTR ;update list pointer AOS (P) ;give successful return RET SUBTTL Search linked list of empty cells ; Find an empty block to store a new variable/option name or a variable value ; ; Accepts: AC1=Addr of start of list ; AC2=#words needed ; ; Returns: AC1=Addr of block ; AC2 preserved SRCHMT: MOVEM .AC1,.AC4 ;save current pointer LOAD .AC1,FWDPTR,BINDEF(.AC1) ;get the address of the next block SKIPG .AC1 ;end of list? JRST [MOVE .AC1,BINDEF+.WRDCNT ;yep then put it at the end MOVEM .AC2,.AC3 ;get word count ADDB .AC3,BINDEF+.WRDCNT ;compute # words in .BIN file CAIL .AC3,BINMAX*1K-1 ;has .BIN file grown too large? JRST SAVFIL ;yep, then file too large IDIVI .AC3,1K+1 ;compute # pages in .BIN file CAMLE .AC3,BINSIZ ;less than or equal to current count? JRST SRCHM1 ;nope, then map another page RET] LOAD .AC3,VALLEN,BINDEF(.AC1) ;get length of block CAMLE .AC2,.AC3 ;will this answer fit here? JRST SRCHMT ;nope, then try again CAME .AC2,.AC3 ;is there any extra left? JRST [SUB .AC3,.AC2 ;yep, then get #words remaining STOR .AC3,VALLEN,BINDEF(.AC1) ;update block length ADD .AC1,.AC3 ;and increment pointer RET] LOAD .AC3,FWDPTR,BINDEF(.AC1) ;get addr of next block STOR .AC3,FWDPTR,BINDEF(.AC4) ;and update previous block RET SRCHM1: PUSH P,.AC1 ;save list addr PUSH P,.AC2 ;save word count MOVE .AC1,.AC3 ;get file page MOVEM .AC1,BINSIZ ;save new page count HRL .AC1,BINJFN ;plus jfn ADDI .AC2,BINDEF/1K ;compute fork page TXO .AC2,PM%RD+PM%WR ;for read and write SETZ .AC3, ;map only one page PMAP% ;map it POP P,.AC2 ;restore word count POP P,.AC1 ;restore list addr RET SUBTTL Get access to a linked list ; Accepts: AC1=RH=addr of start of list, LH=0: read access, -1: write access ; ; Returns: +1 always, access granted ; Uses: AC1, AC2, AC3, AC4, left-half of list address as access flag ACCESS: SKIPN BINJFN ;has SETUP.BIN been mapped yet? CALL ACCMAP ;nope, then map it now MOVEM .AC1,.AC2 ;move list addr to R2 TLZ .AC1,-1 ;mask out left half CAIN .AC1,.VARST ;access desired to variable list? JRST [TXNE F,F%VAC ;yep, then already accessing? RET ;yep then do nothing JRST .+1] ;no, then continue CAIN .AC1,.OPTST ;access desired to option list? JRST [TXNE F,F%OAC ;yep, then already accessing options? RET ;yep then do nothing JRST .+1] ;no, then continue CAIN .AC1,.EMPST ;access desired to empty-cell list? JRST [TXNE F,F%EAC ;yep, then already accessing list? RET ;yep, then do nothing JRST .+1] ;no, then continue MOVEI .AC1,MAXTRY MOVEM .AC1,WAITRY ;set access trial count MOVEI .AC1,1 ;dismiss to get a whole time-slice DISMS% ACCES2: SKIPGE BINDEF(.AC2) ;does someone already have write access? JRST ACCES4 ;yep TLNE .AC2,-1 ;read or write access? JRST ACCES3 ;write HLRZ .AC1,BINDEF(.AC2) ;get read count AOJ .AC1, ;increment it HRLM .AC1,BINDEF(.AC2) ;and store again JRST ACCES5 ACCES3: HLRZ .AC1,BINDEF(.AC2) ;get read count SKIPE .AC1 ;=zero? JRST ACCES4 ;nope, then wait 'till it is MOVNI .AC1,1 HRLM .AC1,BINDEF(.AC2) ;set write access JRST ACCES5 ACCES4: SOSG WAITRY ;list in use, so try again later JRST ACCNGR ;cannot grant access MOVEI .AC1,WAITIM ;how much later? DISMS% JRST ACCES2 ;try again! ACCES5: TLZ .AC2,-1 ;mask out left half of R2 CAIN .AC2,.VARST ;accessing variable list? TXO F,F%VAC ;set flag CAIN .AC2,.OPTST ;accessing option list? TXO F,F%OAC ;set flag CAIN .AC2,.EMPST ;accessing empty-cell list? TXO F,F%EAC ;set flag RET ; Map SETUP.BIN for use by SRCHLL ACCMAP: PUSH P,.AC1 MOVE .AC1,[GJ%OLD+GJ%SHT] HRROI .AC2,[ASCIZ /SETUP.BIN/] GTJFN% JRST [SKIPE BINJFN ;on error skip if not set already JRST BINUNC ;cannot create SETUP.BIN SETOM BINJFN ;avoid looping here! MOVE .AC1,[GJ%SHT] JRST .-2] MOVE .AC2,[OF%RD+OF%WR+OF%THW] OPENF% JRST BINOPN MOVEM .AC1,.AC4 ;save jfn here for a while HRLZ .AC1,.AC1 MOVE .AC2,[.FHSLF,,BINDEF/1K] MOVE .AC3,[PM%RD+PM%WR] PMAP% MOVEI .AC1,.EMPST+1 ;#words min in SETUP.BIN EXCH .AC4,BINJFN ;jfn=>binjfn,binjfn=>4 SKIPE .AC4 ;do we need to initialize SETUP.BIN? MOVEM .AC1,BINDEF ;yep MOVE .AC1,BINDEF ;get word count IDIVI .AC1,1K+1 ;compute page count-1 MOVEM .AC1,BINSIZ ;save the page count SKIPG .AC1 ;skip if more than 1 page JRST ACCMP1 ;else done MOVEM .AC1,.AC3 ;move page count remaining to AC3 MOVEI .AC1,1 ;start mapping w/page 1 now HRL .AC1,BINJFN ;get file jfn MOVE .AC2,[.FHSLF,,<BINDEF/1K>+1] ;map rest of pages after the first TXO .AC3,PM%RD+PM%WR+PM%CNT PMAP% ;map the rest of the file ACCMP1: POP P,.AC1 ;restore list address RET SUBTTL Clear access to a linked list ;Accepts: AC1=RH=addr of start of list ; ;Returns: +1 always, access grated ; ;Uses: AC1, AC2 ; left-half of list address as accesss flag CLRACS: MOVEI .AC1,.VARST ;clear variable list access TXZE F,F%VAC ;skip if not accessing it CALL CLRAC1 ;clear access MOVEI .AC1,.OPTST ;clear option list access TXZE F,F%OAC ;skip if not accessing it CALL CLRAC1 ;clear access MOVEI .AC1,.EMPST ;clear empty-cell list access TXZE F,F%EAC ;skip if not accessing it CALL CLRAC1 ;clear access RET CLRAC1: SKIPG .AC2,BINDEF(.AC1) ;skip if read-only access JRST [HRRZM .AC2,BINDEF(.AC1) ;clear write access RET] HLRZ .AC2,BINDEF(.AC1) ;get read count SOJ .AC2, ;decrement it HRLM .AC2,BINDEF(.AC1) ;and store RET RELBIN: ;un-map, close, and release SETUP.BIN MOVE .AC1,BINJFN ;get jfn HRLI .AC1,.FBSIZ ;modify byte count in FDB MOVNI .AC2,1 MOVE .AC3,BINDEF ;to be word count CHFDB% HRLI .AC1,.FBBYV ;make sure byte size is 36 MOVE .AC2,[77B11] MOVE .AC3,[44B11] CHFDB% MOVNI .AC1,1 MOVE .AC2,[.FHSLF,,BINDEF/1K] SKIPE .AC3,BINSIZ ;get page count, skip if only one page JRST [TXO .AC3,PM%CNT ;else unmap all pages AOJA .AC3,.+1] PMAP% MOVE .AC1,BINJFN CLOSF% ;close the file NOP RET ;**** ERROR TYPE OUT ROUTINES FATAL: TMSG (%) MOVE .AC1,T1 PSOUT% JRST QUIT INIERR: MOVEI T1,[ASCIZ /Error initializing command line parse/] JRST FATAL INICFM: MOVEI T1,[ASCIZ /Unrecognized parameters at end of command/] JRST FATAL INVNAM: MOVEI T1,[ASCIZ /Invalid or missing option name/] JRST FATAL SAVFIL: MOVEI T1,[ASCIZ /Default value file has grown too large/] JRST FATAL ACCNGR: MOVEI T1,[ASCIZ /SETUP.BIN file is in use by another job/] JRST FATAL BINOPN: MOVEI T1,[ASCIZ /Cannot open SETUP.BIN/] JRST FATAL BINUNC: MOVEI T1,[ASCIZ /Unable to create SETUP.BIN/] JRST FATAL ANSW1: BLOCK <MAXCHR/5> ;WORK AREA FOR LINE MUST BE SAME ; LENGTH AS LINE Z ;OVRFLOW TEST ATMBUF: BLOCK <MAXCHR/5> ;COMND atom buffer BINJFN: 0 ;jfn of SETUP.BIN if needed BINSIZ: 0 ;page count of SETUP.BIN ENTVEC: JRST START JRST START ;for REENTER command EXP 3B2+1B11+2 ;version 1(2)-3 ITMPTR: 0 ;a byte pointer to item to be found LINE: BLOCK <MAXCHR/5> ;STORAGE FOR PROCESSING MCF LINE Z ;OVRFLOW TEST WORD-DO NOT MOVE LSTPTR: 0 ;a byte pointer to item in list PDLIST: BLOCK <PDLEN> ;PUSH-DOWN STORAGE SVALUE: 0 ;place to save default/old value WAITRY: 0 ;number of tries for list access CMBLOK: REPARS ;block for COMND BLOCK 6 -1,,ATMBUF ;atom buffer MAXCHR ;size of atom buffer 0 ;no GTJFN block XLIST ;don't list literals LIT LIST BINDEF=.!777+1+2K ;a place to map SETUP.BIN END <3,,ENTVEC>