10 !REACT VERSION 6B EDIT 0 24-FEB-77 ! !IMPROVED VERSION OF REACT TO ALLOW MULTIPLE ENTER/DELETE CAPABILITIES !COUPLED WITH NEW $ACCT.VIR FORMAT. 11 !12-SEP-76 ADD PROVISION FOR LAST RESET DATE TO A1%(). !9-OCT-76 ADD 'BUILD' OPTION TO CREATE $ACCT.VIR FROM MFD/UFD'S !24-FEB-77 ADD 'LIST' TO CREATE ASCCI FILE FROM $ACCT.VIR !29-Aug-77 STOP AND COMMENTS FOR DECUS VERSION. 20 !INSTRUCTIONS: !Program operates similarly to DEC's Cusp by the same name only !with several convenience features. Options are: !ENTER - to enter new accounts !DELETE - to delete accounts !BUILD - to creat $ACCT.VIR from existing accounts on disk. !LIST - to create a file from existing accounts in format expected ! by ENTER, option 3. !STOP - to exit REACT after sorting $ACCT.VIR ! !The program maintains $ACCT.VIR, a virtual array of ppn's and passwords !in order by ppn. This file is used by MONEY and CHANGE; it replaces !the file $ACCT.SYS. $ACCT.VIR is used by REACT, MONEY, and CHANGE !solely for locating ppn's. The other information in the file is !somewhat redundant (except for the LIST option of REACT which !creates its list from this info, rather than using a SYS() call. ! !ENTER: Enter allows the entering of new accounts indvidually, !by group, or from a list. When "group" is selected, a group !of ppn's with random passwords is created, a listing of which !may be directed to some output device (this list is used as !a "sign-up" sheet which we pass out to instructors who then !hand out the numbers to their students). The format for !"file" is that produced by LIST; its used to carry accounts over !from one disk to another after a complete system build. Note !that one dummy file is created and then deleted in each account !to insure the UFD is actually extended. ! DELETE: Deletes single accounts or a whole range of accounts. !Accounts will be zeroed by REACT if they contain files; !for the "group" option, this zeroing can be either automatic !or selective, allowing the system manager to selectively !delete accounts from a group. ! BUILD: Required to build the initial structure of $ACCT.VIR from !existing disk accounts. Program terminates after BUILD and must be !rerun to enter new accounts (this is a precaution to assure the !file is correctly built before other options are allowed.) ! !LIST: To create a file of all numbers in $ACCT.VIR for later use !with the ENTER command: Output format is, ! proj#, prog#, password, quota, cluster ! !NOTE: Program assumes the user is priveleged and therefore knows what !he/she is doing; as a result extensive error handling of "dumb" !errors (like letters where digits are expected) is limited. ! !PROGRAM RESTRICTION: Because we have only a single system disk, !this proogram as written does not support private packs; hopefully !the program comments are sufficient to allow this feature to be !included by those who require it. (in particular line 4030 &5010, !as well as how to handle the dependence on $ACCT.VIR). ! 900 DIM A%(1023%,3%),S1%(30%),S2%(30%),A(1023%),P%(1023%) ! !A%() COPY COLUMN 1-4 OF A1%(). !S1%() FOR FIP CALLS !S2%() FOR FIP CALLS !A() P,PN'S (COL 1 OF A1%()). !P%() POINTERS IN QUICKSORT. 910 DIM#1, A1%(1023%,4%) ! !A1%(0,0) # OF ACCOUNT CURRENTLY ! (0,1) N%, WHERE DATE$(N%) IS DATE OF LAST SYSTEM RESET. ! (I,0) P,PN OF ACC'T I; (PEEK() FORMAT) ! (I,1) RAD50 PASSWORD, PART 1 911 ! (I,2) RAD50 PASSWORD, PART 2 ! PASSWORD=RAD$(A1%(I,1))+RAD$(A1%(I,2)) ! (I,3) QUOTA ! (I,4) UFD CLUSTERSIZE. ! 1000 PRINT 'REACT VERSION 6B-00' \GOSUB 11000 \ON ERROR GOTO 19000 !IDENTIFY AND INITIALIZE FILES AND PARAMETERS. 1010 PRINT Q3$;'ENTER, DELETE, BUILD, LIST, OR STOP'; \INPUT K$ \ K$=LEFT(CVT$$(K$,255%),1%) \ON INSTR(1%,'EDBLS',K$)+1% GOTO 1010,2000,3000,6000,7000,8500 ! BAD ENTER DEL BUILD LIST STOP 2000 ! ! E N T E R N E W A C C O U N T S ! 2010 INPUT 'INDIVIDUAL(1), GROUP(2), FILE(3)';K% \ON K% GOTO 2100, 2200, 2300 ! IND. GROUP FILE 2100 INPUT '[P,PN]';P1%,P0% \INPUT 'PASSWORD';P$ \INPUT 'QUOTA, UFD CLUSTER';Q%,C% \GOSUB 4000 \GOTO 2100 !ENTERING OF INDIVIDUAL ACCOUNT NUMBERS. 2200 INPUT 'GROUP PROJ.#';P1% \INPUT '1ST, LAST PROG.#';P8%,P9% \INPUT '3-LETTER PASWORD PREFIX';P0$ \P0$=CVT$$(P0$,255%) \INPUT 'QUOTA';Q% !PARAMETER FOR CONTINUOUS RANGE OF ACCOUNT NUMBERS. 2210 PRINT 'LISTING FILE'; \INPUT LINE K$ \ K$=CVT$$(K$,255%) \IF LEN(K$)=0% THEN Z0%=0% ELSE Z0%=-1% \OPEN K$ FOR OUTPUT AS FILE 3% !GET NAME OF OPTIONAL LISTING FILE. 2220 FOR P0%=P8% TO P9% \P$=CVT$$(P0$+RIGHT(NUM$(1000%+INT(1000%*RND)),3%),2%) \GOSUB 4000 \IF Z0% THEN PRINT#3%, Q3$;FNP$(P1%,P0%);TAB(10%);P$;TAB(20%); STRING$(40%,95%) !ENTER ACCOUNT; ADD TO LISTING FILE (IF REQUESTED). 2230 NEXT P0% \CLOSE 3% IF Z0% \Z0%=0% \GOTO 2200 !CLOSE LISTING FILE (IF OPEN) RETURN FOR ANOTHER GROUP. 2300 PRINT 'FILENAME'; \INPUT LINE K$ \ K$=CVT$$(K$,255%) \OPEN K$ FOR INPUT AS FILE 2% \K1$='TEMP00.TMP' !LIST OF ACCOUNTS IN AN ASCII FILE; FORMAT IS: ! P,PN,PASSWORD,QUOTA,UFD CLUSTER 2310 WHILE -1% \INPUT#2%, P1$,P0$,P$,Q%,C% \P1%=VAL(P1$) \ P0%=VAL(P0$) \GOSUB 4000 \GOSUB 2500 \NEXT !GET LINE AT A TIME AND ENTER ACCOUNT UNTIL EOF REACHED; OTHER !ERRORS CAUSE ONLY THAT ACCOUNT TO BE SKIPPED. 2320 CLOSE 2% \PRINT Q3$;"ALL ACCOUNTS IN FILE '";K$;"', EXCEPT THOSE LISTED ABOVE"; Q3$;"(IF ANY) HAVE BEEN ENTERED.";Q3$ \GOTO 2000 !LET USER KNOW IT WORKED. 2500 K2$='['+P1$+','+P0$+']'+K1$ \OPEN K2$ FOR OUTPUT AS FILE 4% \KILL K2$ \CLOSE 4% \RETURN !INSERTED TO PRE-EXTEND UFD IF CREATING FROM A LIST. 3000 ! ! D E L E T E A C C O U N T S ! 3010 INPUT 'INDIVIDUAL(1) OR RANGE(2)';K% \INPUT 'ZERO ACCOUNTS AUTOMATICALLY (YES OR NO)';K$ \K$=LEFT(CVT$$(K$,255%),1%) \IF K$='Y' THEN Z0%=-1% ELSE Z0%=0% !Z0% FLAG TO ZERO ACCOUNTS NOT ALREADY ZEROED. 3020 ON K% GOTO 3100, 3200 ! IND. RANGE ! 3100 INPUT '[P,PN] TO DELETE';P1%,P0% \GOSUB 5000 \GOTO 3100 !DELETE ACCOUNT ONE AT A TIME. 3200 INPUT 'GROUP PROJ.#';P1% \INPUT '1ST, LAST PROG.# OF RANGE TO DELETE';P8%,P9% \GOSUB 5000 FOR P0%=P8% TO P9% \GOTO 3200 !ALLOWS DELETION OF CONSECUTIVE #'S OF SAME GROUP. 4000 ! ! S U B R O U T I N E T O E N T E R A C C O U N T ! 4010 S1%(I%)=0% FOR I%=3% TO 30% \S1%(0%)=30% \S1%(1%)=6% \S1%(2%)=0% \S1%(7%)=P0% \S1%(8%)=P1% !2 - ENTER ACCOUT SYS CALL; 7 - PROG#; 8 - PROJ# 4020 CHANGE SYS(CHR$(6%)+CHR$(-10%)+P$) TO S2% \S1%(I%+2%)=S2%(I%) FOR I%=7% TO 10% !PUT RAD50 FORM OF PASSWORD INTO BYTES 9 TO 12 OF CALLING STRING. 4030 S1%(13%)=Q% AND 255% \S1%(14%)=SWAP%(Q%) AND 255% \S1%(27%)=C% AND 255% \S1%(28%)=SWAP%(C%) AND 255% !ENTER QUOTA AND UFD CLUSTER INTO CORRECT SLOTS; !NOTE: 23-26 ARE ZERO ==> ONLY SY0: CURRENTLY SUPPORTED. 4040 CHANGE S1% TO S$ \S$=SYS(S$) !DO THE SYS CALL TO ENTER AN ACCOUNT. 4050 A0%=A0%+1% \A%(A0%,0%)=S1%(9%)+SWAP%(S1%(10%)) \A%(A0%,1%)=S1%(11%)+SWAP%(S1%(12%)) \A%(A0%,2%)=Q% \A%(A0%,3%)=C% \A(A0%)=256.*P1%+P0% !ADD NEW ACCOUNT IN IN CORE COPY OF '$ACCT.VIR'. 4060 RETURN !END OF ENTER ACCOUNT ROUTINE. 4100 ! ! E N T E R A C C O U N T E R R O R S ! 4110IF ERR=2% THEN PRINT Q9$;FNP$(P1%,P0%);" NOT ENTERED - BAD PASSWORD '"; P$;"'." \RETURN !ILLEGAL FILENAME ERROR FOR EITHER SYS CALL ==> BAD PASSWORD. 4120 IF ERR=4% THEN PRINT Q3$;Q9$;'MFD IS FULL -- NO MORE ACCOUNTS.' \GOTO 8500 !NO ROOM FOR USER ==> NO ROOM FOR MORE ACCOUNTS. 4130 IF ERR=10% THEN PRINT Q9$;FNP$(P1%,P0%);' NOT ENTERED - ILLEGAL [P,PN]' \RETURN !PROTECTION VIOLATION ==> PPN IS NO GOOD. 4140 IF ERR=16% THEN PRINT Q9$;FNP$(P1%,P0%); ' ACCOUNT ALREADY EXISTS.' \RETURN !NAME OR ACCOUNT ALREADY EXISTS ERROR. 4150 PRINT Q9$;FNP$(P1%,P0%);' ';FNE$(ERR) \IF ERR=23% THEN RETURN ELSE PRINT'FATAL ERROR - PROGRAM STOPPING.' \STOP !23 IS BAD CLUSTERSIZE; ANYTHING ELSE IS FATAL. 5000 ! ! D E L E T E A C C O U N T S U B R O U T I N E ! 5010 S1%(I%)=0% FOR I%=0% TO 30% \S1%(0%)=30% \S1%(1%)=6% \S1%(2%)=1% \S1%(7%)=P0% \S1%(8%)=P1% !(1) - DELETE ACCOUNT SYS CALL; (7)=PROG# ; (8)=PROJ# 5020 CHANGE S1% TO S$ \S$=SYS(S$) !DO THE SYS CALL; ANY ERRORS (IN PARTICULAR NON-ZEROED ACCOUNT) !ARE TRAPPED BEFORE RESUMING HERE. 5030 P=256.*P1%+P0% \L%=1% \R%=A0% !P IS PEEK() FORM OF P,PN; PROJ#'S >=128 CAUSE A NEGATIVE VALUE !P IS UNSIGNED VALUE OF 16BIT P%. 5040 WHILE L%<=R% \M%,M1%=(L%+R%)/2% \M%=M%-1% WHILE A(M%)=65535. \IF PA(M%) THEN L%=M1%+1% ELSE L%=R%+1% !BINARY SEARCH SKIPPING DELETED ELEMENTS; LAST LINE FORCES EXIT !ON MATCH. 5050 NEXT \IF P=A(M%) THEN A(M%)=65535. ELSE PRINT Q9$;FNP$(P1%,P0%);" NOT IN '$ACCT.VIR' - "; "ACCOUNT DELETED ANYWAY." !MAKE SURE SEARCH TERMINATED SUCCESFULLY. 5060 RETURN !END OF DELETE ACCOUNT ROUTINE. ! 5100 ! ! D E L E T E A C C O U N T E R R O R S ! 5110 IF ERR<>3% THEN PRINT Q9$;FNP$(P1%,P0%);' -- ';FNE$(ERR) \IF ERR=5% OR ERR=10% THEN RETURN ELSE PRINT 'FATAL ERROR. '; \ STOP !ERR=3 FOR NON-ZEROED ACCOUNT; 5 - NO SUCH ACCOUNT; !10 - P,PN OF 0,0 OR 0,1 OR 1,1. 5120 IF Z0% THEN PRINT "ACCOUNT ";FNP$(P1%,P0%);" BEING ZEROED." ELSE PRINT "ZERO ";FNP$(P1%,P0%);" (YES OR NO)"; \INPUT K$ \ K$=LEFT(CVT$$(K$,255%),1%) \IF K$<>'Y' THEN PRINT 'KEEPING ACCOUNT ';FNP$(P1%,P0%) \RETURN !ZERO IT? 5130 S2%(I%)=0% FOR I%=3% TO 30% \S2%(0%)=30% \S2%(1%)=6% \S2%(2%)=13% \S2%(5%)=P0% \S2%(6%)=P1% !SET UP FOR ZERO ACCOUNT SYS CALL; 5 = PROG#; 6 = PROJ#. 5140 CHANGE S2% TO S$ \S$=SYS(S$) \PRINT 'ACCOUNT ';FNP$(P1%,P0%);' NOW ZEROED; WILL NOW DELETE IT.' \GOTO 5020 !GO BACK TO DELETE ACCOUNT SYS CALL. ! 6000 ! ! B U I L D O P T I O N ! 6010 S1%(0%)=30% \S1%(1%)=6% \S1%(2%)=14% \S1%(I%)=0% FOR I%=5% TO 30% !INIT FOR ACCOUNT INFO LOOKUP (BY INDEX) 6020 FOR A0%=1% UNTIL A0%>1023% \S1%(3%)=A0% AND 255% \S1%(4%)=SWAP%(A0%) AND 255% \CHANGE S1% TO S$ \CHANGE SYS(S$) TO S2% !GET INFO FROM THE A0%-TH P,PN IN THE MFD. 6030 A(A0%)=256.*S2%(8%)+S2%(7%) \A%(A0%,0%)=S2%(9%)+SWAP%(S2%(10%)) \A%(A0%,1%)=S2%(11%)+SWAP%(S2%(12%)) \A%(A0%,2%)=S2%(27%)+SWAP%(S2%(28%)) \A%(A0%,3%)=S2%(29%) !PUT INFO INTO CORE ARRAYS. 6040 NEXT A0% !CONTINUE UNTIL ERR=5 ==> NO MORE ACCOUNTS ON THE SYSTEM. 6050 A0%=A0%-1% \PRINT A0%;'ACCOUNTS NOW IN $ACCT.VIR '; '-- PROGRAM WILL HALT AFTER SORTING THE FILE.' \GOTO 8500 !EXIT PROGRAM AFTER A BUILD (PROGRAM LIMITATION). 7000 ! ! L I S T $ A C C T . V I R I N E N T E R F O R M ! 7010 PRINT'LISTING FILE'; \INPUT LINE K$ \ K$=CVT$$(K$,4%) \OPEN K$ FOR OUTPUT AS FILE 3% !GET NAME AND OPEN THE LISTING FILE (WILL BE IN ENTER FROM LIST !FORM). 7020 FOR I%=1% TO A0% \PRINT#3%, SWAP%(A1%(I%,0%))AND 255%;','; A1%(I%,0%) AND 255%;','; RAD$(A%(I%,0%));RAD$(A%(I%,1%));','; A%(I%,2%);',';A%(I%,3%) !PRINT THE LINE 7030 NEXT I% \CLOSE 3% \PRINT A0%;'ACCOUNTS LISTED TO FILE ';K$;Q3$ \GOTO 1010 !CLOSE UP AND RETURN FOR OPTION. 8000 ! ! Q U I C K S O R T O F [ P , P N ] ! ! NOTE: THE AMBITIOUS PROGRAMMER MAY WISH TO REPLACE ! THIS QUICKSORT WITH A METHOD WHICH SORTS ONLY THE NEW ! ENTRIES AND THEN MERGES THESE INTO THE OLD ENTRIES. ! QUICKSORT IS FINE WHEN BUILDING $ACCT.VIR THE FIRST TIME ! BUT IT IS INAPPROPRIATE WHEN SIMPLY ADDING A FEW NEW ! ACCOUNTS. 8010 P%(I%)=I% FOR I%=1% TO A0% \P%=0% \ L%=1% \ R%=A0% !INITIALIZE FOR QUICKSORT OF [P,PN]'S; $ACCT.VIR ALWAYS IN ORDER !TO SPEED UP MONEY AND CHANGE PROGRAMS. 8020 IF R%-L%<10% THEN GOSUB 8100 \RETURN UNLESS P% \L%=S1%(P%) \R%=S2%(P%) \P%=P%-1% \GOTO 8020 !IF RUN IS SHORT, DO INSERTION SORT AND GET NEXT PIECE OFF STACK !ALL DONE IF STACK EMPTY. 8030 I%=L% \J%=R% \GOSUB 8200 \T=A(K%) \P0%=P%(K%) \A(K%)=A(J%) \P%(K%)=P%(J%) !SELECT PARTIONING ELEMENT (T) AND INIT FOR EXCHANGE SORT ABOUT T. 8040 I%=I%+1% WHILE A(I%)<=T AND I%T AND I%R%-J% THEN S1%(P%)=L% \S2%(P%)=I%-1% \L%=J%+1% \GOTO 8020 !PUSH LONG PIECE ONTO STACK AND CONTINUE WITH SHORTER ONE. 8070 S1%(P%)=J%+1% \S2%(P%)=R% \R%=I%-1% \GOTO 8020 !HERE THE RIGHT PIECE IS LONGER; SO PUSH IT AND CONTINUE ON LEFT. 8100 FOR I%=L%+1% TO R% \T=A(I%) \P0%=P%(I%) !SUBROUTINE TO INSERTION SORT A SMALL BUNCH (<=10). ASSUME A(0)=-1, !LESS THAN ALL OTHER A(); ALSO A(L) IS < A(I), FOR ALL I>=L+1. 8110 FOR J%=I%-1% STEP -1% WHILE TA0% OR A(I%)=65535. \IF A(I%)<32767. THEN A1%(I%,0%)=A(I%) ELSE A1%(I%,0%)=A(I%)-65536. ![P,PN] STORED AS 256.*P + PN IN A(I); HENCE MUST CONVERT TO !SIGNED INTEGER FOR STORAGE IN A1%(I,0). 8520 J%=P%(I%) \A1%(I%,J1%)=A%(J%,J1%-1%) FOR J1%=1% TO 4% !A1%(I,1) & A1%(I,2) = RAD50 PASSWORD !A1%(I,3) = QUOTA !A1%(I,4) = UFD CLUSTER SIZE. !P%() IS POINTER ROW OF A%() CORRESPONDING TO PPN IN A(). 8530 NEXT I% \A1%(0%,0%)=I%-1% \CLOSE 1% \GOTO 32767 !UPDATE NUMBER OF ACTIVE ACCOUNTS AND QUIT ! ! ! 10000 ! ! F U N C T I O N S & S U B R O U T I N E S ! 10100 DEF FNE$(E%)=CVT$$(RIGHT(SYS(CHR$(6%)+CHR$(9%)+CHR$(E%)),3%),4%) !FUNCTION TO PRINT AN ERROR MESSAGE. 10200 DEF FNP$(P1%,P0%)=CVT$$('['+NUM$(P1%)+','+NUM$(P0%)+']',2%) !FUNCTION TO FORM '[P,PN]' FROM TWO INTEGER ARGUMENTS. 11000 ! ! I N I T I A L I Z A T I O N ! 11010 ON ERROR GOTO 11050 \OPEN '$ACCT.VIR' FOR INPUT AS FILE 1% \A0%=A1%(0%,0%) !OPEN $ACCT.VIR (TRAP TO 11040 IF IT DOESN'T EXIT YET.) 11020 FOR I%=1% TO A0% \A(I%)=A1%(I%,0%) \ A(I%)=65536.+A(I%) IF A(I%)<0% \A%(I%,J%)=A1%(I%,J%+1%) FOR J%=0% TO 3% \NEXT I% !COPY '$ACCT.VIR' TO IN CORE ARRAYS TO SPEED PROCESSING. 11030 Q3$=CHR$(13%)+CHR$(10%) \Q9$='?ERROR -- ' \A(0%)=-1. \RANDOMIZE \S$=SYS(CHR$(6%)+CHR$(-7%)) !RANDOMIZE FOR GROUP ENTER OPTION; SET CTRL/C TRAP. 11040 RETURN !END OF INITIALIZATION ROUTINE. ! 11050 IF ERR<>5% THEN 19000 ELSE OPEN '$ACCT.VIR' FOR OUTPUT AS FILE 1%, FILESIZE 20% \A1%(0%,1%),A0%=0% \RESUME 11030 !ERROR TRAP IF '$ACCT.VIR' DOES NOT EXIST AT THIS TIME. ! 19000 ! ! G E N E R A L E R R O R R O U T I N E ! 19010 IF ERR=28% THEN RESUME 1010 ELSE IF ERR=11% THEN IF ERL=2310% THEN RESUME 2320 ELSE RESUME 1010 !CTRL/C OR CTRL/Z RETURNS TO MAIN QUESTION. 19020 IF ERL>=4000% AND ERL<=4099% THEN RESUME 4100 ELSE IF ERL>=5000% AND ERL<=5099% THEN RESUME 5100 !ENTER/DELETE ROUTINES HANDLE THERE OWN ERRORS. 19030 IF ERR=5% AND ERL=6020% THEN RESUME 6050 !LOOKUP ON INDEX DURING BUILD HAS GONE BEYOND LIMIT. 19100 PRINT FNE$(ERR);' AT LINE';ERL \IF ERL<4000% THEN RESUME 1010 ELSE STOP !SOME SORT OF ERROR AT BEGINNING, TRY AGAIN; OTHERWISE DISASTER. ! 32767 END