; -*-MIDAS-*- TITLE DSKUSE -- DSK INFO -- PDL 2/19/76 ;9/6/79 Modified for new TUT format (ITS 1154) ; note to the perplexed: The value of the symbol ; MAXUSR (currently 512.) controls how many users DSKUSE can handle. ; since this is the maximum number of directories ITS can have in the ; current implementation, this should be enough. .MLLIT=1 ; ==================================================================== ; accumulator definitions ; ==================================================================== A=1 B=2 C=3 D=4 E=5 F=6 G=7 H=10 I=11 J=12 K=13 L=14 M=15 N=16 ARGP=16 P=17 TYIC==1 ; channels TYOC==2 CH==3 MCH==4 TCMD==5 ; command output channel ; disk system variables .INSRT SYSTEM;FSDEFS > %USRBLK==8 ; size of single user info block %USER==0 ; offsets of data %FILES==1 %LINKS==2 %BLCKS==3 %QUOTA==4 %ALLOC==5 %PACKN==6 %BLKAV==7 ; command macro DEFINE COM DIS,NMS IRP NM,,[NMS] SIXBIT \!NM!\ PUSHJ P,DIS TERMIN TERMIN ; fix and float macros DEFINE FLOAT AX,AY TLC AX,232000+1000*AY FADR AX,AX TERMIN DEFINE FIX AX,AY MULI AX,400 TSC AX,AX ASH AX+1,AY-243(AX) TERMIN ; ==================================================================== ; :dskuse ? ; ==================================================================== CINFO: ASCIZ \ DSKUSE is usually driven by a command from its JCL line, as follows: :DSKUSE user statistics on the user directory given, or the MSNAME directory if no argument. :DSKUSE > user print message if MSNAME user (or user given explicitly) is over quota, else nothing. :DSKUSE @ file statistics on all users output to TPL:, or to file if given. :DSKUSE & file output two tables, sorted on user and blocks, to TPL: or to file if given. :DSKUSE # general statistics on disk system (takes time). :DSKUSE $ same as previous, only less detailed (faster, too). :DSKUSE % user print % of directory space used by user. :DSKUSE * statistics on all users, in tabular form. this command is special in that it leaves you in DSKUSE. you may type the number or name of a column to sort by that column and then reprint the table (0 or USER, 1 or FILES, etc.). in this mode the @ command, with a file name optionally following it, causes subsequent sorts to go to the file. the commands #, %, and > are not available. The dual sort (& or BOTH) is, however. For more details see .INFO.;DSKUSE INFO.\ INFO: OASCR CINFO JRST KILL ; ==================================================================== ; DSKUSE ; ==================================================================== START: MOVE P,[-100,,PDL] ; set up pdl ; here to open ttys .OPEN TYIC,[SIXBIT / TTYFOOBARBLECH /] .VALUE [ASCIZ /:CANT OPEN TTY/] .OPEN TYOC,[SIXBIT / !TTYXXXXXXYYYYYY/] .VALUE [ASCIZ !:CANT OPEN TTY!] .OPEN TCMD,[SIXBIT / 1TTYXXXXXXYYYYYY/] .VALUE [ASCIZ !:CANT OPEN TTY!] ; set up TTY interrupt .CALL [SETZ 'TTYGET 1000,,TYIC 2000,,A 402000,,B] .VALUE [ASCIZ /:CANT GET CONSOLE TYPE/] ; make only ^G and ^S interrupt MOVE 0,[SIXBIT / !!!!!/] ANDCAM 0,A MOVE 0,[SIXBIT / !!!!!/] ANDCAM 0,B .CALL [SETZ 'TTYSET 1000,,TYIC A 400000,,B] .VALUE [ASCIZ /:CANT SET CONSOLE TYPE/] ; enable interrupt MOVEI A,1 ; tty int SETZ B, .SETM2 A, ; get msname of user .SUSET [.RSNAM,,RSYSNM] MOVE RSYSNM MOVEM USRNAM ; get command from superior .SUSET [.ROPTIO,,A] TLNN A,40000 ; OPTCMD JRST HUSER .BREAK 12,[5,,COMMND] SKIPN COMMND JRST HUSER ; no argument ; got arg, so parse it MOVE [440700,,COMMND] MOVEM COMPTR PUSHJ P,GETSYL ; get command, if any JUMPE B,HUSER ; dispatch MOVE A,SWPTR JCLOOP: CAMN B,(A) JRST @1(A) AOS A AOBJN A,JCLOOP MOVEM B,USRNAM JRST OUSER ; assume funny user ; ==================================================================== ; jcl line command table ; ==================================================================== SWTABL: COM AUSER,[&] ; two column, user and blocks sorted COM AUSER1,[@] ; one column, user, to tpl COM AUSER2,[*] ; one column, no tpl COM DSKDAT,[$] ; quick statistics COM QUSER,[#] ; detailed statistics COM UFULL,[%] ; percent of dir used COM UFULLB,[%%] ; dir bloated? COM UOVER,[>] ; quota check COM INFO,[?] ; info SWPTR: -<<.-SWTABL>/2>,,SWTABL ; ==================================================================== ; :DSKUSE % ; ==================================================================== UFULLB: SETOM UFULLF' UFULL: PUSHJ P,GETSYL SKIPE B MOVEM B,USRNAM .SUSET [.SSNAM,,USRNAM] ; read ufd in .OPEN CH,UDIR JRST NOUFD MOVE A,[-2000,,FDIR] .IOT CH,A .CLOSE CH, PUSHJ P,UFULL0 JRST KILL UFULL0: MOVE D,UDESCP+FDIR MOVEI C,UDDESC+FDIR ; ; D/ desc count HRLI C,440600 ; "BYTE PTR" SETZ B, ; "COUNT" NEXTA: SETZ A, NEXTB: SOJL D,FEND ILDB C JUMPE NBYTE ; "ZERO BYTE?" SETOM A ; "NON-ZERO BYTE" JRST NEXTB ; "LOOP" NBYTE: JUMPN A,NEXTA ; "ZERO, WAS LAST ZERO?" SETZM A AOJA B,NEXTB ; "AOS NULL COUNT" FEND: MOVE C,UDESCP+FDIR SUB C,B IDIVI C,6 ; "NUMBER OF WORDS" ADDI C,2000 SUB C,UDNAMP+FDIR FLOAT C MOVEI B,2000-UDDESC FLOAT B FDVR B,[100.0] FDVR C,B SKIPN UFULLF JRST UFULLP CAMGE C,[97.0] POPJ P, UFULLP: OASC [ASCIZ /Directory /] OSIX USRNAM OASC [ASCIZ / is /] JUMPE C,UEMPTY OFLOAT C OASCR [ASCIZ /% full./] POPJ P, UEMPTY: OASCR [ASCIZ /empty./] POPJ P, ; ==================================================================== ; :DSKUSE > ; ==================================================================== UOVER: PUSHJ P,GETSYL SKIPE B MOVEM B,USRNAM .SUSET [.SSNAM,,USRNAM] PUSHJ P,USRDSK JRST KILL MOVE B,UBLCKS CAMG B,UQUOTA JRST KILL SUBM B,UQUOTA OASCR [0] OSIX USRNAM OASC [ASCIZ / OVER QUOTA BY /] ODEC UQUOTA OASCR [ASCIZ / BLOCKS/] JRST KILL ; ==================================================================== ; :DSKUSE # ; ==================================================================== QUSER: PUSHJ P,DSKAV PUSHJ P,GATHER PUSHJ P,DATOUT OASCR [0] PUSHJ P,QSKOUT JRST KILL ; ==================================================================== ; :DSKUSE % ; ==================================================================== ; here for general data DSKDAT: PUSHJ P,DSKAV ; get system data PUSHJ P,DATOUT ; print system data JRST KILL ; exit ; ==================================================================== ; :DSKUSE ; ==================================================================== ; here for just doing this user HUSER: .SUSET [.RSNAM,,USRNAM] JRST EUSER ; ==================================================================== ; :DSKUSE ; ==================================================================== ; here for specified user OUSER: SKIPE USRNAM .SUSET [.SSNAM,,USRNAM] ; common area for single user dskuse EUSER: OASCR [0] PUSHJ P,DSKAV ; get data on system as whole PUSHJ P,USRDSK ; get data on single user JRST NOUFD ; print data for single user PUSHJ P,UFULL0 ;OASC [ASCIZ /User /] ;OSIX USRNAM ;OASCR [0] OASC [ASCIZ /Files /] ODECR UFILES OASC [ASCIZ /Links /] ODECR ULINKS OASC [ASCIZ /Blocks /] ODEC UBLCKS SKIPN UPACKN JRST EUQOTA OASCR [0] OASC [ASCIZ/Allocated to pack /] ODEC UPACKN ;Attempt to extract pack name out of the system MOVE A,UPACKN MOVE B,NQS SUBI B,1 CAME A,QPKID(B) SOJGE B,.-1 JUMPL B,EUQOTA SKIPE A,TRESRV(B) CAMN A,[-1] JRST EUQOTA OASC [ASCIZ/ (/] OSIX A OASC [ASCIZ/:)/] EUQOTA: SKIPG A,UQUOTA JRST EUSBLK CAMGE A,UBLCKS OASCI "* EUSBLK: OASCR [0] SKIPG UALLOC JRST EUSERQ OASC [ASCIZ \Allocation \] ODECR UALLOC EUSERQ: MOVE A,UALLOC CAMN A,UQUOTA JRST EUSYST OASC [ASCIZ \Quota \] ODECR UQUOTA ; print data for system as a whole EUSYST: OASC [ASCIZ \Free Blocks \] SKIPG FREEBL JRST EUSYS1 ; here if there are allocations OASCR [0] OASC [ASCIZ \ Unallocated \] ODECR FRUNAL OASC [ASCIZ \ Allocated \] ODEC FREEBL EUSYS2: OASC [ASCIZ \ of \] ODECR ALLBL OASC [ASCIZ \Average User \] ODECR AVER JRST KILL ; exit ; here if there are no allocations EUSYS1: ODEC FRUNAL JRST EUSYS2 ; ==================================================================== ; :DSKUSE & ; ==================================================================== AUSER: SETOM BOTH ; set & flag ; ==================================================================== ; :DSKUSE @ ; ==================================================================== ; here to output table to disk AUSER1: PUSHJ P,SCNAME PUSHJ P,DSKOUT ; open disk channel SETOM JCLFLG ; ==================================================================== ; :DSKUSE * ; ==================================================================== ; here to output table to tty after finishing AUSER2: SETZB G,H SETZ I, OASCR [0] ; get data on date, time, and system name ; what system are we on? .CALL RDSYST JFCL ; time .RTIME A, MOVEM A,TIME ; date .RDATE A, ROT A,12. MOVEM A,DATE ; optional sort number 0 => 5 PUSHJ P,GETSYL LDB A,[360600,,B] SUBI A,20 CAIL A,0 CAILE A,5 ; 6 columns SETZ A, SKIPE A MOVEM A,SORTX ; sort on what entry in vector? HRRM A,SORTX ; enter loop here to get users and status them one after another ; out of mfd PUSHJ P,DSKAV PUSHJ P,GETMFD PUSHJ P,GATHER ; here to frob all ufd's HRRI N,USERS ; save aobjn to users MOVEM N,CPTR ; calculate blocks/file MOVE A,TBL MOVE B,TFL FLOAT A, FLOAT B, FDVR A,B MOVEM A,TAV JRST ENDST1 ; call block for .call /sstatu/ RDSYST: SETZ SIXBIT /SSTATU/ 2000,,0 2000,,0 2000,,0 2000,,0 2000,,0 SETZM SYSNAM ; * print * ENDST1: SKIPL BOTH JRST ONESRT ; * here for & dskuse (0 & 3 sort at once) * ; do 3 sort (blocks) MOVEI A,3 MOVE M,CPTR PUSHJ P,VSORT ; move results into second data vector MOVE M,CPTR HRRI M,FDIR MOVEM M,CPTR1 MOVE A,[USERS,,FDIR] BLT A,FDIR+MAXUSR-1 ; do 0 sort MOVSI A,-1 MOVE M,CPTR PUSHJ P,VSORT JRST PRTSRT ; print results ; * do single sort * ONESRT: MOVE A,SORTX ; sort key MOVE M,CPTR ; cptr PUSHJ P,VSORT ; do it ; here to print sort PRTSRT: OASCI ^L ; form feed OASCR [0] ; herald message OSIX SYSNAM OASC [ASCIZ \ DISK USAGE by \] OSIX RSYSNM OASC [ASCIZ \ at \] OTIME TIME OASC [ASCIZ \ on \] ODATE DATE OASCR [0] OASCR [0] ; general system data PUSHJ P,DATOUT OASCR [0] SKIPN BOTH JRST COLHDR PUSHJ P,QSKOUT OASCR [0] ; column header(s) COLHDR: OASCR [0] PUSHJ P,TYPHDR SKIPN BOTH JRST ONEHDR ; here to type extra header for & mode OASC [ASCIZ \ \] PUSHJ P,TYPHDR OASCR [0] ; underline appropriate column headers OASC [ASCIZ \---- \] SKIPG TQUO JRST COLHD1 OASCI ^I COLHD1: SKIPG TALLO JRST COLHD2 OASCI ^I COLHD2: OASCR [ASCIZ \ ------\] JRST TYPSTT ; start normal typeout ; here to underline normal header ONEHDR: OASCR [0] HRRZ B,SORTX XCT PTABS(B) ; appropriate tabs OASCR [0] ; here to start typing user stats TYPSTT: OASCR [0] MOVE D,CPTR MOVE G,CPTR1 ; loop TYPNXT: MOVE A,(D) PUSHJ P,TYPOUT SKIPN BOTH JRST TYPEND OASC [ASCIZ \ \] MOVE A,(G) PUSHJ P,TYPOUT TYPEND: OASCR [0] ADD G,[1,,1] AOBJN D,TYPNXT ; done, type totals OASCR [0] PUSHJ P,TYPTOT SKIPN BOTH JRST TYPGET ; type extra total, for second list in & dskuse OASC [ASCIZ \ \] PUSHJ P,TYPTOT ; form feed if in & mode SKIPE BOTH OASCI ^L ; prepare to get a command TYPGET: SETZM BOTH ; here to get a command typed from tty, after we have performed ; the single command that could be given when dskuse was invoked. TYPCOM: SKIPE JCLFLG' JRST KILL .IOT TCMD,["*] MOVE N,M PUSHJ P,READ PUSHJ P,GETSYL MOVE A,TYPPTR TYPLUP: CAMN B,(A) JRST @1(A) AOS A AOBJN A,TYPLUP BADCOM: .IOT TCMD,["?] .IOT TCMD,["?] .IOT TCMD,[^M] .IOT TCMD,[^J] JRST TYPCOM TYPTAB: COM KILL,[Q,QUIT,KILL] COM DSKOPN,[@] COM DSKOP1,[&] COM SRTUSR,[0,U,USER] COM SRTFIL,[1,F,FILE,FILES] COM SRTLNK,[2,L,LINK,LINKS] COM SRTBLK,[3,B,BLK,BLOCK,BLOCKS] COM SRTQUO,[4,Q,QUO,QUOTA,QUOTAS] COM SRTALL,[5,A,ALL,ALLOC,ALLOCA] COM SRTPCK,[6,P,PACK] COM SRTAVG,[7,R,RATIO,B/F,BF,AVG] TYPPTR: -<<.-TYPTAB>/2>,,TYPTAB ; ==================================================================== ; sort commands ; ==================================================================== SRTUSR: MOVEI A,0 JRST SORTIT SRTFIL: MOVEI A,1 JRST SORTIT SRTLNK: MOVEI A,2 JRST SORTIT SRTBLK: MOVEI A,3 JRST SORTIT SRTQUO: MOVEI A,4 JRST SORTIT SRTALL: MOVEI A,5 JRST SORTIT SRTPCK: MOVEI A,6 JRST SORTIT SRTAVG: MOVEI A,7 ; if name column, sort "backwards" SORTIT: SKIPN A HRLI A,-1 ; sort "frontwards" MOVEM A,SORTX ; set up sort key JRST ENDST1 ; output a double sort DSKOP1: SETOM BOTH JRST ENDST1 ; ==================================================================== ; output rest of sorts to disk ; ==================================================================== DSKOPN: PUSHJ P,SCNAME ; cons up output file spec PUSHJ P,DSKOUT ; open it JRST TYPCOM ; loop ; here to reopen "TTY" channel to "DSK" DSKOUT: .SUSET [.SSNAM,,RSYSNM] MOVEI '! HRLM OUTPUT .OPEN TYOC,OUTPUT .VALUE [ASCIZ !:CANT OPEN OUTPUT FILE!] POPJ P, ; here to exit by killing job and not typing anything EXIT: .VALUE [ASCIZ /:KILL  /] KILL: .BREAK 16,140000 HEADER: ASCIZ \USER Files Links Blocks\ HEADE1: ASCIZ \ Quota\ HEADE2: ASCIZ \ Alloc\ HEADE3: ASCIZ \ Pack\ HEADE4: ASCIZ \ B/F\ TYPHDR: OASC HEADER SKIPE TQUO OASC HEADE1 SKIPE TALLO OASC HEADE2 OASC HEADE3 OASC HEADE4 POPJ P, PTABS: OASC [ASCIZ /----/] OASC [ASCIZ / -----/] OASC [ASCIZ / -----/] OASC [ASCIZ / ------/] OASC [ASCIZ / -----/] OASC [ASCIZ / -----/] OASC [ASCIZ / ----/] OASC [ASCIZ / ---/] ; * type total line * TYPTOT: OASC [ASCIZ \Total \] OJUST 3,TFL OASCI ^I OJUST 3,TLK OASCI ^I OJUST 4,TBL OASCI ^I SKIPG TQUO JRST TYPTO1 OJUST 4,TQUO OASCI ^I TYPTO1: SKIPG TALLO JRST TYPTO2 OJUST 4,TALLO OASCI ^I OASCI ^I TYPTO2: OFLOAT TAV POPJ P, ; * output general data * DATOUT: OASC [ASCIZ \Total number of users is \] ODEC TUS SKIPG TQUO JRST DATUAL OASC [ASCIZ \, \] ODEC TUQUOT OASC [ASCIZ \ with quotas\] DATUAL: SKIPG TALLO JRST DATUSR OASC [ASCIZ \, \] ODEC TUALLO OASC [ASCIZ \ with allocations\] DATUSR: OASCR [0] SKIPG TQUO JRST DATAVG OASC [ASCIZ \Over quota: \] ODEC TPIGS OASC [ASCIZ \ users, \] ODEC TFAT OASC [ASCIZ \ blocks, average excess \] ODEC TBACON OASC [ASCIZ \ blocks each\] OASCR [0] DATAVG: OASC [ASCIZ \Average blocks per user \] ODEC AVER SKIPG TQUO JRST DATALO OASC [ASCIZ \, per quota'ed user \] ODEC TAQUOT DATALO: SKIPG TALLO JRST DATFRE OASC [ASCIZ \, per allocated user \] ODEC TAALLO DATFRE: OASCR [0] OASC [ASCIZ \Free disk blocks: \] ODEC FRUNAL SKIPG TALLO JRST DATOUX OASC [ASCIZ \ unallocated, \] ODEC FREEBL OASC [ASCIZ \ allocated\] DATOUX: OASCR [0] OASC [ASCIZ \Disk system contains \] ODEC NQS OASC [ASCIZ \ disks\] MOVE A,NQS CAMN A,NQSONL JRST DATOUY OASC [ASCIZ \ (\] ODEC NQSONL OASC [ASCIZ \ on-line)\] DATOUY: OASC [ASCIZ \, \] ODEC ALLBL OASCR [ASCIZ \ blocks\] OASC [ASCIZ \Free swapping blocks: \] ODEC FREESW OASC [ASCIZ \ out of \] ODECR SWAPAL OASC [ASCIZ \Unused UFD slots: \] MOVE A,NUDSL SUB A,TUS SETZ B, BLT B, SKIPE B ;If this is a KL10 or a KS10, it has a SUBI A,2 ; front-end file system in blocks 0,1 ODEC A OASC [ASCIZ \ of \] MOVE A,NUDSL SKIPE B SUBI A,2 ODECR A POPJ P, ; here to output tables of disk crufties QSKOUT: OASC [ASCIZ \Drive \] SETZ K, QSKTOP: CAML K,NQS JRST QSKEND OASC [ASCIZ \DK\] ODEC K OASC [ASCIZ \: \] AOJA K,QSKTOP QSKEND: OASCR [0] OASCR [0] OASC [ASCIZ \Pack # \] MOVEI B,QPKID PUSHJ P,QTABL1 OASC [ASCIZ \Disk size \] MOVEI B,TLASTB PUSHJ P,QTABL1 OASCR [0] OASC [ASCIZ \Available \] MOVEI B,TSIZES PUSHJ P,QTABL1 ; only print alloc if there is some SKIPG TALLO JRST QFREEP OASC [ASCIZ \Allocated \] MOVEI B,PACK PUSHJ P,QTABL1 QFREEP: OASC [ASCIZ \Free space \] MOVEI B,QSFT PUSHJ P,QTABL1 OASCR [0] OASC [ASCIZ \Swap area \] MOVEI B,TSWAPA HLL B,QPTR MOVE D,QPTR HRRI D,QACT QSWAPT: SKIPE (D) JRST QSWAP1 MOVE C,(B) SUB C,NUDSL SKIPGE C MOVEI C,0 OJUST 5,C QSWAP2: OASCI ^I AOBJN D,.+1 AOBJN B,QSWAPT OASCR [0] OASC [ASCIZ \Free swap area \] MOVEI B,QSFTS PUSHJ P,QTABL1 POPJ P, QSWAP1: OASC [ASCIZ / --/] JRST QSWAP2 QTABL1: PUSH P,C MOVE C,QPTR HRRI C,QACT HLL B,QPTR QTABL3: SKIPE (C) JRST QTABL2 OJUST 5,(B) QTABL4: OASCI ^I AOBJN C,.+1 AOBJN B,QTABL3 OASCR [0] POP P,C POPJ P, QTABL2: OASC [ASCIZ \ --\] JRST QTABL4 QTABLE: HLL B,QPTR OJUST 5,(B) OASCI ^I AOBJN B,QTABLE+1 OASCR [0] POPJ P, ; point at user vector -- up to MAXUSR users GATHER: MOVEI A,USERS MOVEM A,N MOVEM A,M ; ptr to vector ; zero total of users SETZM TUS ; users SETZM TPIGS ; users over quota SETZM TFAT ; total excess SETZM TBACON ; average excess PUSHJ P,GETMFD GATHE1: PUSHJ P,MFDN ; get a user id into C JRST GATHEX JUMPE C,GATHE1 ; loop if empty slot MOVEM C,USRNAM ; username .SUSET [.SSNAM,,C] ; set to it ; individual user stats PUSHJ P,USRDSK JRST GATHE1 PUSHJ P,USRVEC ; add to vector AOS TUS JRST GATHE1 ; loop GATHEX: MOVE A,TFAT ; calculate avg blks for pigs MOVE B,TPIGS PUSHJ P,AVG MOVEM A,TBACON MOVE A,TBQUOT ; calculate avg blks for quota MOVE B,TUQUOT PUSHJ P,AVG MOVEM A,TAQUOT MOVE A,TBALLO ; calculate avg blks for alloc MOVE B,TUALLO PUSHJ P,AVG MOVEM A,TAALLO POPJ P, ; average, given total and number of instances (as fixes), return a fix AVG: PUSH P,B FLOAT A FLOAT B FDVR A,B FIX A MOVE A,B POP P,B POPJ P, ; * here to get average number of blocks per user on disk * ;This comment is wrong! ; makes a good guess at number of free blocks on disks by finding out ; number of packs, and number of free blocks on each, subtracting that from ; number of packs times 5000 blocks per pack minus 200 ufd blocks and 1 mfd, 1 tut ; per pack. ; Puts results out in ALLBL (total number of blocks) ; and FREEBL (number of blocks free) DSKAV: PUSHJ P,QNUM ; how many packs PUSHJ P,QRES ; any reserved? PUSHJ P,DSKALL ; total disk blocks PUSHJ P,DSKFRE ; free disk blocks PUSHJ P,SWPFRE ; free swapping blocks PUSHJ P,DSKMFD ; get # of users, blocks/user POPJ P, ; * number of packs in system * ; nqs/ # of packs ; qtuto/ -n,,qtuto ; tutsiz/ # of blocks per tut QNUM: PUSH P,A MOVE A,[SQUOZE 0,NQS] .EVAL A, .VALUE [ASCIZ /:.EVAL OF NQS FAILED/] MOVEM A,NQS MOVNS A HRLS A HRRI A,QTUTO MOVEM A,QPTR ; get number blocks for a tut MOVE A,[SQUOZE 0,NTUTBL] .EVAL A, .VALUE [ASCIZ /:.EVAL OF SYMBOL IN A FAILED/] MOVEM A,TUTSIZ POP P,A POPJ P, ; any reserved packs in system?? QRES: PUSH P,A MOVE A,[SQUOZE 0,QRSRVP] SETOM TUTRSR .EVAL A, SETZB A,TUTRSR MOVEM A,QRSRVP POP P,A POPJ P, ; * free blocks in system * ; freebl/ free blocks in system DSKFRE: PUSH P,A PUSH P,B MOVE A,[QSFT,,[SQUOZE 0,QSFT]] PUSHJ P,GETQ MOVEI B,QSFT PUSHJ P,QTOTAL MOVEM A,FREEBL MOVEI B,0 HLL B,QPTR SETZ A, DSKFR1: SKIPE TRESRV(B) JRST DSKFR2 SKIPL QSFT(B) ADD A,QSFT(B) DSKFR2: AOBJN B,DSKFR1 MOVEM A,FRUNAL MOVNS A ADDM A,FREEBL POP P,B POP P,A POPJ P, ; * free swapping blocks * ; freesw/ free swapping blocks SWPFRE: PUSH P,A PUSH P,B MOVE A,[QSFTS,,[SQUOZE 0,QSFTS]] PUSHJ P,GETQ MOVEI B,QSFTS PUSHJ P,QTOTAL MOVEM A,FREESW POP P,B POP P,A POPJ P, ; * getloc of (in ac A) symbol to symbol+nqs * ; qtuto/ first pack ; ... ; qtuto+nqs-1/ last pack GETQ: PUSH P,B MOVE B,QPTR HLR B,A MOVE A,(A) .EVAL A, .VALUE [ASCIZ /:.EVAL OF SYMBOL IN A FAILED/] HRLS A HRR A,B .GETLOC A, ADD A,[1,,1] AOBJN B,.-2 POP P,B POPJ P, ; A/ ,, symbol GETUT: PUSH P,B PUSH P,C HRLZ C,A ; C/ symbol,,0 HLRZ A,A ; A/ table nqs long MOVE B,QPTR ; B/ -nqs,,qtuto SIZLUP: HRL A,(B) ADD A,C ; offset by QTUTO .GETLOC A, AOS A AOBJN B,SIZLUP POP P,C POP P,B POPJ P, ; * allocations * ; swapal/ swapping allocation ; allbl/ total of system blocks DSKALL: PUSH P,A PUSH P,B PUSH P,C PUSH P,D ; read in qtuto table MOVE A,[QTUTO,,[SQUOZE 0,QTUTO]] PUSHJ P,GETQ ; find out which packs are active MOVE A,[QACT,,[SQUOZE 0,QACT]] PUSHJ P,GETQ ; now total on-line disk packs SETZ A, MOVEI B,QACT HLL B,QPTR SKIPN (B) ; offline? AOS A AOBJN B,.-2 MOVEM A,NQSONL ; find out pack numbers for each drive MOVE A,[QPKID,,[SQUOZE 0,QPKID]] PUSHJ P,GETQ ; find out which packs are allocated SKIPN TUTRSR ; reservations in tut? JRST OLDRSR MOVE A,[TRESRV,,QTRSRV] SKIPE QRSRVP ; any reserved packs in system? PUSHJ P,GETUT JRST GSWAPA OLDRSR: MOVE A,[TRESRV,,[SQUOZE 0,QRESRV]] PUSHJ P,GETQ ; else in table ; get size of packs GSWAPA: MOVE A,[TLASTB,,QLASTB] PUSHJ P,GETUT ; get swapping allocations MOVE A,[TSWAPA,,QSWAPA] PUSHJ P,GETUT ; start by getting number of ufds MOVE A,[SQUOZE 0,NUDSL] .EVAL A, .VALUE [ASCIZ /:.EVAL OF NUDSL FAILED/] MOVEM A,NUDSL ; get total swapping allocation, fixed up by removing blocks ; allocated for UFDs HLLZ C,QPTR MOVEI B,0 GSWAP1: SKIPE QACT(C) JRST GSWAP2 MOVE A,TSWAPA(C) SUB A,NUDSL SKIPLE A ADD B,A GSWAP2: AOBJN C,GSWAP1 MOVEM B,SWAPAL ; calculate total blocks per pack MOVE B,QPTR HRRI B,TLASTB MOVE C,QPTR HRRI C,TSWAPA MOVE D,QPTR HRRI D,TSIZES DSKTOT: MOVE A,(B) ; get greater of nudsl and swapa into 0 MOVE 0,NUDSL CAMGE 0,(C) MOVE 0,(C) SUB A,0 ; subtract mfd and tut if not already part of swapa CAIGE 0,2500. SUB A,TUTSIZ ; flush tut blocks MOVEM A,(D) AOBJN B,.+1 AOBJN C,.+1 AOBJN D,DSKTOT ; calculate total blocks by adding all packs MOVEI B,TSIZES PUSHJ P,QTOTAL MOVEM A,ALLBL ; restore acs and return POP P,D POP P,C POP P,B POP P,A POPJ P, ; total a table nqs long -- ignore inactive packs QTOTAL: PUSH P,C MOVE C,QPTR HRRI C,QACT HLL B,QPTR SETZ A, QTOTA1: SKIPE (C) JRST QTOTA2 SKIPL (B) ADD A,(B) QTOTA2: AOBJN C,.+1 AOBJN B,QTOTA1 POP P,C POPJ P, ; total users and average per user ; aver/ average blocks per user ; tus/ total users DSKMFD: PUSH P,A PUSH P,B SKIPE B,TUS JRST DSKMF1 PUSHJ P,GETMFD PUSHJ P,MFDN SKIPA AOJA B,.-2 MOVEM B,TUS ; now compute average blocks per user DSKMF1: MOVE A,ALLBL SUB A,FREEBL IDIV A,B MOVEM A,AVER .CLOSE MCH, POP P,B POP P,A POPJ P, ; * next username from mfd * ; C/ username in sixbit MFDN: AOS MFDPTR AOS C,MFDPTR CAILE C,MFDPTR+1777 POPJ P, SKIPN C,(C) JRST MFDN AOS (P) POPJ P, ; * add info on a user to free block * ; get 6 word block USRVEC: MOVEI A,%USRBLK ADDB A,FREEPT ; put out data MOVE 0,USRNAM ; username MOVEM 0,%USER(A) MOVE 0,UFILES ; # files MOVEM 0,%FILES(A) MOVE 0,ULINKS ; # links MOVEM 0,%LINKS(A) MOVE 0,UBLCKS ; # blocks MOVEM 0,%BLCKS(A) MOVE 0,UQUOTA ; quota MOVEM 0,%QUOTA(A) MOVE 0,UALLOC MOVEM 0,%ALLOC(A) MOVE 0,UPACKN MOVEM 0,%PACKN(A) MOVE 0,UBKFLS ; blocks/file MOVEM 0,%BLKAV(A) ; update cptr to pointers MOVEM A,(N) SUB N,[(1)] ADDI N,1 POPJ P, ; * typeout information on a given user * ; a/ ptr to data block TYPOUT: PUSH P,A PUSH P,B MOVE B,A ; type out data OSIX %USER(B) ; user-id OASCI ^I OJUST 3,%FILES(B) ; # file OASCI ^I OJUST 3,%LINKS(B) ; # links OASCI ^I OJUST 4,%BLCKS(B) ; # blocks ; give him a * if over quota SKIPE TQUO SKIPG A,%QUOTA(B) ; has quota? JRST TYPBLK CAMGE A,%BLCKS(B) OASCI "* TYPBLK: SKIPG TQUO JRST TYPALC SKIPG TALLO JRST TYPOU1 OASCI ^I SKIPG %ALLOC(B) JRST TYPQUO ; here if has alloc. (print quota only if different) TYPALL: MOVE A,%QUOTA(B) CAMN A,%ALLOC(B) JRST TYPAL1 OJUST 4,%QUOTA(B) TYPAL1: OASCI ^I OJUST 4,%ALLOC(B) JRST TYPOU1 ; here if only has quota TYPQUO: OJUST 4,%QUOTA(B) OASCI ^I ; restore acs and return TYPOU1: OASCI ^I SKIPE %PACKN(B) OJUST 2,%PACKN(B) OASCI ^I OFLOAT %BLKAV(B) ; blocks/file POP P,B POP P,A POPJ P, TYPALC: SKIPG TALLO JRST TYPOU1 OASCI ^I OJUST 4,%ALLOC(B) JRST TYPOU1 ; * read in mfd * GETMFD: SKIPE MFDBUF+MDNAMP JRST GETMFX .OPEN MCH,MFDDIR .VALUE [ASCIZ !:CANT OPEN M.F.D.!] MOVE A,[-2000,,MFDBUF] .IOT MCH,A JUMPL A,TINY .CLOSE MCH, GETMFX: MOVE A,MFDBUF+MDNAMP ADDI A,MFDBUF-2 ; aos's first, cretin... MOVEM A,MFDPTR POPJ P, TINY: .VALUE [ASCIZ !:M.F.D. LESS THAN 2000 WORDS LONG?!] ; * single user statistics gatherer * NOUFD: OASCI "" OSIX USRNAM OASCR [ASCIZ \" is not the name of a directory.\] JRST KILL USRDSK: PUSH P,D PUSH P,E ; read ufd in .OPEN CH,UDIR JRST USRLSR MOVE A,[-2000,,FDIR] .IOT CH,A .CLOSE CH, ; initialize world SETZB C,D SETZB E,F SETZM UFILES SETZM ULINKS SETZM UBLCKS SETZM UBKFLS SETZM UQUOTA SETZM UALLOC SETZM UPACKN SETZM OLDC ; quota and number of blocks MOVE B,FDIR+UDBLKS HLREM B,UQUOTA SKIPGE B SETZM UQUOTA HRREM B,UBLCKS SKIPG A,UQUOTA JRST L69 CAML A,UBLCKS JRST L69 MOVE A,UBLCKS SUB A,UQUOTA ADDM A,TFAT AOS TPIGS ; pack and allocation L69: HRRE B,FDIR+UDALLO SKIPLE B ; if negative or zero (UALLOC is 0 already) MOVEM B,UALLOC HLRZ E,FDIR+UDALLO JUMPE E,L105 MOVEM E,UPACKN SKIPN TUTRSR JRST O69 MOVE A,QPTR ; here for new style reservations HLLZ A,A ; done by pack number rather than drive DRLOOP: SKIPL QACT(A) ; drive off line? CAME E,QPKID(A) JRST DRNEXT ADDM B,PACK(A) JRST L105 DRNEXT: AOBJN A,DRLOOP JRST L105 O69: ADDM B,PACK(E) ; for old style reservation hackery L105: MOVE B,UDNAMP+FDIR ADDI B,FDIR L1: CAILE B,FDIR+1773 JRST UNUM SKIPN (B) JRST NEXTFL MOVE E,UNRNDM(B) TLNE E,UNIGFL JRST NEXTFL TLNE E,1 AOSA ULINKS ; was a link AOS UFILES ; was a regular file ; move to next file NEXTFL: ADDI B,LUNBLK JRST L1 ; finish calculations and exit ; calculate blocks/file UNUM: MOVE A,UBLCKS FLOAT A MOVE B,UFILES FLOAT B FDVR A,B MOVEM A,UBKFLS ; add to totals SKIPLE E,UFILES ADDM E,TFL SKIPLE E,ULINKS ADDM E,TLK SKIPLE E,UBLCKS ADDM E,TBL SKIPG UALLOC JRST UPDUSR AOS TUALLO ; here for allocated directory ADDM E,TBALLO JRST UPDUS1 UPDUSR: SKIPG UQUOTA JRST UPDUS1 AOS TUQUOT ; here for quota'ed directory ADDM E,TBQUOT UPDUS1: SKIPLE E,UQUOTA ADDM E,TQUO SKIPLE E,UALLOC ADDM E,TALLO ; go here if no files in dir ZEROES: AOS -2(P) USRLSR: POP P,E POP P,D POPJ P, ; byte pointer table DESCBP: 440600 360600 300600 220600 140600 060600 ; * buffers * MAXUSR==512. USERS: BLOCK MAXUSR ; this is largest number of users prog will handle FREEPT: FREESP+1-%USRBLK FREESP: BLOCK MAXUSR*%USRBLK ; free storage buffer PDL: BLOCK 100 FDIR: BLOCK 2000 BUF: BLOCK 20. ; variables SORTX: -1,,0 CPTR: 0 CPTR1: 0 OLDC: 0 ; * variables used for getting system info * TUTRSR: 0 ; non-zero if new style reservation stuff TUTSIZ: 0 ; number of blocks in tut (NTUTBL) NQS: 0 ; number of packs NQSONL: 0 ; number of packs online QPTR: 0 ; -nqs,,qtuto QRSRVP: 0 ; any reserved packs? NUDSL: 0 ; number of ufds allowed QTUTO: BLOCK 10 ; location of tut for drives TLASTB: BLOCK 10 ; drive sizes (rp02 or rp03) TRESRV: BLOCK 10 ; reserved? (-1 if is) TSWAPA: BLOCK 10 ; swapping allocations QACT: BLOCK 10 ; disk active? QPKID: BLOCK 10 ; pack numbers TSIZES: BLOCK 10 ; calculated sizes (exclude ufds and mfd and tut) QSFT: BLOCK 10 ; free file space QSFTS: BLOCK 10 ; free swap space PACK: BLOCK 10 ; total allocated on each drive ; * status variables * ; single user totals USRNAM: 0 ; user UFILES: 0 ; # of files ULINKS: 0 ; # of links UBLCKS: 0 ; number of blocks in ufd UBKFLS: 0 ; blocks/file average UQUOTA: 0 ; quota UALLOC: 0 ; allocation UPACKN: 0 ; allocated pack number ; system wide totals TUS: 0 ; total # users TUALLO: 0 ; total # allocated users TUQUOT: 0 ; total # quota'ed users TPIGS: 0 ; users over quota TFAT: 0 ; total excess for TPIGS TBACON: 0 ; average pigness of TPIGS TFL: 0 ; total files TLK: 0 ; total links TBL: 0 ; total blocks TBALLO: 0 ; total blocks in allocated directories TBQUOT: 0 ; total blocks in quota'ed directories TAV: 0 ; average b/f over system TAALLO: 0 ; average b/u for allocated directories TAQUOT: 0 ; average b/u for quota'ed directories TQUO: 0 ; total of quotas TALLO: 0 ; total of allocations ; block for cretinous mfd MFDPTR: 0 MFDBUF: BLOCK 2000. ; disk system stats FREESW: 0 ; free swapping blocks SWAPAL: 0 ; swapping allocation FREEBL: 0 ; free disk blocks FRUNAL: 0 ; free unallocated blocks ALLBL: 0 ; total number of blocks AVER: 0 ; average number of blocks per user directory DATE: 0 ; date dskuse was run TIME: 0 ; time dskuse was run ; * I/O variables * BOTH: 0 ; flag for double dskuse ("&") ; files UDIR: SIXBIT / &DSK.FILE.(DIR) / MFDDIR: SIXBIT / &DSKM.F.D.(FILE)/ OUTPUT: SIXBIT / !TPLDSKUSEOUTPUT/ RSYSNM: 0 ; sname of user SYSNAM: 0 ; which system? dm, ai, or ml? ; ================================================================ ; read a command line ; ================================================================ COMMND: BLOCK 20 COMPTR: 0 ; set up buffer READ: PUSH P,A PUSH P,B SETZM COMMND MOVE [COMMND,,COMMND+1] BLT 0,COMPTR-1 ; command reader RCMD: MOVE B,[440700,,COMMND] MOVEM B,COMPTR MOVEI C,0 RCMD1: .IOT TYIC,A CAIN A,177 JRST RUB CAIN A,^D JRST RREPEA CAIN A,^L JRST RCLEAR CAIN A,^J JRST RCMD1 CAIN A,^Q JRST RQUOTE CAIN A,^M JRST RCMDX RCMDL: IDPB A,B CAMGE B,[350700,,COMMND+17] AOJA C,RCMD1 RCFUL: IDPB A,B MOVEI A,15 IDPB A,B RCMDX: IDPB A,B MOVEI A,0 IDPB A,B POP P,B POP P,A POPJ P, RREPEA: .IOT TCMD,[^M] .IOT TCMD,[^J] JRST REPPER RCLEAR: .IOT TCMD,[^P] .IOT TCMD,["C] REPPER: .IOT TCMD,["*] MOVEI A,COMMND HRLI A,440700 REP1: ILDB A JUMPE RCMD1 .IOT TCMD, JRST REP1 RQUOTE: IDPB A,B CAML B,[350700,,COMMND+17] JRST RCFUL SETOM QUTFLG AOS C .IOT TYIC,A SETZM QUTFLG' JRST RCMDL RUB: PUSHJ P,RUBBER JRST RCMD JRST RCMD1 RUBBER: SOJL C,[POPJ P,] ; erasure rubout handler MOVEI A,0 DPB A,B .IOT TCMD,[^P] .IOT TCMD,["X] ADD B,[070000,,] TLNE B,400000 ADD B,[347777,,-1] AOS (P) POPJ P, ; =================================================================== ; command line reading and parsing section ; =================================================================== ; read a file spec SCNAME: PUSH P,D MOVEI D,OUTPUT PUSH P,A PUSH P,B PUSH P,C MOVSI C,-2 HRRI C,1(D) JRST SCNONE SCNGET: HRRZ A,(D) CAIE A,'TPL JRST SCNONE MOVEI A,'DSK HRRM A,(D) SCNONE: PUSHJ P,GETSYL JUMPE B,SCNX CAIE A,': JRST .+3 HLRZM B,(D) JRST SCNGET CAIE A,'; JRST SCNNMN MOVEM B,3(D) JRST SCNGET SCNNMN: MOVEM B,(C) JUMPL A,SCNX CAIE A,', AOBJN C,SCNGET SCNX: POP P,C POP P,B POP P,A POP P,D POPJ P, ; get a syllable from command buffer GETSYL: PUSH P,C PUSH P,[0] MOVEI B,(P) HRLI B,440600 GETSLP: PUSHJ P,GETCCA JUMPL A,GETSX SETO E, CAIN A,^Q JRST GETQOT SUBI A,40 JUMPL A,GETSX JUMPE A,GETSP CAIN A,'_ JRST GETSX CAIE A,': CAIN A,'; JRST GETSX GETSPT: CAIL A,100 SUBI A,40 TLNN B,770000 JRST GETSLP IDPB A,B JRST GETSLP GETQOT: ILDB A,COMPTR SUBI A,40 JUMPGE A,GETSPT JRST GETSX GETSP: TLNE B,400000 JRST GETSLP GETSX: POP P,B ; character word POP P,C POPJ P, GETCCA: ILDB A,COMPTR JUMPE A,GETCCX CAIN A,^I MOVEI A,40 CAIN A,^M JRST GETCCX CAIN A," MOVEI A,", POPJ P, GETCCX: SETOM A POPJ P, ; ================================================================ ; interrupt handler (tty only) ; ================================================================ ZZZ=. LOC 42 JSR TSINT LOC ZZZ TSINT: 0 0 PUSH P,A MOVEI A,TYIC .ITYIC A, JRST TSDIS CAIE A,^G CAIN A,^S JRST TSKILL ; if ^S or ^G typed, quit TSDIS: POP P,A .DISMIS TSINT+1 TSKILL: .IOT TYIC,A POP P,A .DISMIS [BADCOM] ; ================================================================ ; uuo handler (typeout uuos) ; ================================================================ ZZZ==. LOC 40 0 JSR UUOH LOC ZZZ UUOCT==0 UUOTAB: JRST ILUUO IRPS X,,[OSIX OASC OASCI OASCR ODEC ODECR OFLOAT OJUST ODATE OTIME] UUOCT==UUOCT+1 X=UUOCT_33 JRST U!X TERMIN UUOMAX==.-UUOTAB UUOD: 0 ; contents of UUO eff addr. UUOE: 0 ; UUO effad. UUOH: 0 PUSH P,A PUSH P,B PUSH P,C PUSH P,D MOVEI @40 ; get eff addr. of uuo MOVEM UUOE MOVE @0 MOVEM UUOD ; contents of eff adr MOVE B,UUOE ; eff adr LDB A,[270400,,40] ; get uuo ac, LDB C,[330600,,40] ; op code CAIL C,UUOMAX MOVEI C,0 ; grt=>illegal JRST @UUOTAB(C) ; go to proper rout UUORET: POP P,D POP P,C POP P,B POP P,A ; restore ac's JRST 2,@UUOH ILUUO: .VALUE [ASCIZ /:ILLEGAL UUO/] UOASCR: SKIPA C,[^M] ; cr for end of type UOASC: MOVEI C,0 ; no cr HRLI B,440700 ; make ascii pointer UOASC1: ILDB A,B ; get char JUMPE A,.+3 ; finish? PUSHJ P,IOTA JRST .-3 ; and get another SKIPE A,C ; get saved cr? PUSHJ P,IOTA JRST UUORET UOASCI: MOVE A,B ; prt ascii immediate PUSHJ P,IOTA JRST UUORET UOSIX: MOVE B,UUOD USXOOP: JUMPE B,UUORET LDB A,[360600,,B] ADDI A,40 PUSHJ P,IOTA LSH B,6 JRST USXOOP TENS: 0 ? 10. ? 100. ? 1000. ? 10000. ? 100000. UOJUST: MOVE B,UUOD TYOJ1: CAML B,TENS(A) JRST UOJUS1 .IOT TYOC,[40] SOJG A,TYOJ1 UOJUS1: SETZB A,D MOVEI C,10. JRST UOOCTI+1 UODECR: SKIPA D,[^M] UODEC: SETZ D, MOVEI C,10. JRST .+3 UOOCT: SETZ D, MOVEI C,8. ; octal base MOVE B,UUOD ; get actual word to prt JRST .+3 ; join code UODECI: SKIPA C,[10.] ; decimal UOOCTI: MOVEI C,8. MOVEM C,BASE' SKIPN A HRREI A,-1 ; a=digit count PUSHJ P,UONUM ; print numbr SKIPE A,D PUSHJ P,IOTA JRST UUORET UONUM: IDIV B,BASE HRLM C,(P) ; save digit SOJE A,UONUM1 ; done if 0 SKIPG A ; + => more SKIPE B ; - => b=0 => done PUSHJ P,UONUM ; else more UONUM1: HLRZ C,(P) ; retreive digits ADDI C,"0 ; make to ascii CAILE C,"9 ; is it good dig ADDI C,"A-"9-1 ; make hex digit PUSHJ P,IOTC POPJ P, ; ret UOFLOA: PUSH P,E PUSH P,F PUSH P,G PUSH P,H PUSH P,I MOVE A,UUOD MOVE D,A PUSHJ P,NFLOT POP P,I POP P,H POP P,G POP P,F POP P,E JRST UUORET ; at this point we enter code abstracted from DDT. NFLOT: JUMPE A,FP1A TFL1: MOVEI B,0 CAMGE A,FT01 JRST FP4 CAML A,FT8 AOJA B,FP4 FP1A: FP3: SETZB C,TEM1 ; CLEAR DIGIT CNTR, C TO RECEIVE FRACTION MULI A,400 ASHC B,-243(A) MOVE A,B PUSHJ P,FP7 PUSH P,A MOVEI A,". PUSHJ P,IOTA POP P,A MOVNI A,3 ADD A,TEM1 MOVE E,C FP3A: MOVE D,E MULI D,12 PUSHJ P,FP7B SKIPE E AOJL A,FP3A POPJ P, ; ONE return from OFLT here FP4: MOVNI C,6 MOVEI F,0 FP4A: ADDI F,1(F) XCT FCP(B) SOSA F FMPR A,@FCP+1(B) AOJN C,FP4A PUSH P,EXPSGN(B) PUSHJ P,FP3 PUSH P,A MOVEI A,"E PUSHJ P,IOTA POP P,A POP P,D MOVE A,D PUSHJ P,IOTA MOVE A,F FP7: SKIPE A ; AVOID AOSING TEM1, NOT SIGNIFICANT DIGIT AOS TEM1 IDIVI A,12 HRLM B,(P) JUMPE A,FP7A1 PUSHJ P,FP7 FP7A1: HLRZ D,(P) FP7B: ADDI D,"0 PUSH P,A MOVE A,D PUSHJ P,IOTA POP P,A POPJ P, ; constants 1.0^32. 1.0^16. FT8: 1.0^8 1.0^4 1.0^2 1.0^1 FT: 1.0^0 1.0^-32. 1.0^-16. 1.0^-8 1.0^-4 1.0^-2 FT01: 1.0^-1 FT0=FT01+1 TEM1: 0 ; instructions FCP: CAMLE A, FT0(C) CAMGE A, FT(C) 0, FT0(C) EXPSGN: "- "+ ; ==================================================================== ; uuo character output ; ==================================================================== IOTC: PUSH P,A MOVE A,C PUSHJ P,IOTA POP P,A POPJ P, IOTA: CAIN A,^P JRST IOTAP IOTA1: CAIE A,^J .IOT TYOC,A CAIN A,^M .IOT TYOC,[^J] POPJ P, IOTAP: .IOT TYOC,["^] ADDI A,100 JRST IOTA1 ; type time UOTIME: MOVEI C,": JRST UOTUPL ; type date UODATE: MOVEI C,"/ UOTUPL: LDB A,[360600,,UUOD] ADDI A,40 PUSHJ P,IOTA LDB A,[300600,,UUOD] ADDI A,40 PUSHJ P,IOTA PUSHJ P,IOTC LDB A,[220600,,UUOD] ADDI A,40 PUSHJ P,IOTA LDB A,[140600,,UUOD] ADDI A,40 PUSHJ P,IOTA PUSHJ P,IOTC LDB A,[060600,,UUOD] ADDI A,40 PUSHJ P,IOTA LDB A,[000600,,UUOD] ADDI A,40 PUSHJ P,IOTA JRST UUORET ; ==================================================================== ; sorter ; ==================================================================== ; simple interchange sort ; A/ sort forward or backward (-1/0) VSORT: PUSH P,A PUSH P,G PUSH P,M MOVE F,[CAMG G,(C)] SKIPL A MOVE F,[CAML G,(C)] HRRZS A MOVE D,M POP D,(D) AOS D MOVEM D,E VSORT1: SETZM K MOVE D,E AOBJP D,.+1 SOS D MOVEM D,E VSORT2: AOBJP D,VSORTX MOVE C,(D) ADD C,A MOVE B,-1(D) ADD B,A MOVE G,(B) XCT F JRST VSORT2 EXCH G,(D) EXCH G,-1(D) EXCH G,(D) JUMPL K,VSORT2 SETOM K MOVEM D,E POP E,(E) POP E,(E) HRRZ B,E HRRZ C,M CAMGE B,C AOBJN E,.+1 JRST VSORT2 VSORTX: JUMPL K,VSORT1 POP P,M POP P,G POP P,A POPJ P, END START