.MCALL .MODULE .MODULE DIRSRT,VERSION=04,COMMENT=,IDENT=NO ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ; DIR (Directory Program) ; ; HISTORY ; ; 003 was on 5.6 sources ; ; 004 21-OCT-1996 Tim Shoppa ; Substantial changes throughout. Now supports sorting ; on full 4-digit years. Replaced bubble sort with ; heapsort. Sort entry data structure replaced. .NLIST .LIST .PSECT SORT .SBTTL Local data definitions ;+ ; ; The following data is used only by the routines associated with the sort. ; ;- ;We change the order of the fields inside a sort block to make ;004 ;each sort most convenient. This eliminates nasty branches ;004 ;inside the guts of the sort routine. ;004 ; ;004 ;In particular: ;004 ; ;004 SRTORD: .RAD50 /NAM/ ;004 .BYTE 4 ;004 .BYTE DE.FN1, DE.FN2, DE.TYP, DE.STR, DE.DAT, DE.LEN, DE.ST ;004 SRTOR2: .RAD50 /TYP/ ;004 .BYTE 6 ;004 .BYTE DE.TYP, DE.FN1, DE.FN2, DE.STR, DE.DAT, DE.LEN, DE.ST ;004 .RAD50 /DAT/ ;004 .BYTE 6 ;004 .BYTE DE.DAT, DE.FN1, DE.FN2, DE.TYP, DE.STR, DE.LEN, DE.ST ;004 .RAD50 /SIZ/ ;004 .BYTE 6 ;004 .BYTE DE.LEN, DE.FN1, DE.FN2, DE.TYP, DE.STR, DE.DAT, DE.ST ;004 .RAD50 /POS/ ;004 .BYTE 6 ;004 .BYTE DE.STR, DE.FN1, DE.FN2, DE.TYP, DE.LEN, DE.DAT, DE.ST ;004 SRTOEL == SRTOR2-SRTORD ;004 ; There's no real need to do any re-arranging in a sort by position, ;004 ; but I include it in the above table for consistency. ;004 ; ;004 ; In the case of a /REVERSE sort, we negatize the last 4 or 6 words ;004 ; of the sort field. This makes the resulting output inverted ;004 ; in the one desired field, but forward in the other fields. ;004 ; ;004 ; As a further complication, if we are sorting on date, the ;004 ; date word is stored in the sort block in a rationalized form. ;004 ; We convert to/from this rationalized form even if not sorting on ;004 ; date: ;004 ; ;004 ; Bits 15-9:Year - 1972. ;004 ; Bits 8-5:Month (1-12) ;004 ; Bits 4-0:Day of month (1-31) ;004 DIRDUM: .WORD 0,0,0,0,0,0,0 ;Temporary directory entry ;004 SBLKSZ = 16 ;14. bytes per sort block ;004 QUO: .WORD 0 ;# of lines in listing = FCNT DIV SWC REM: .WORD 0 ;# of items left over = FCNT MOD SWC INK: .WORD 0 ;Offset from 1st entry on a line to the next ;entry = ((FCNT DIV SWC) +1) * SBLKSZ ;If the current column > REM, INK is actually ; INK - SBLKSZ. .SBTTL SRTDRV- Sorted listing generator ;+ ; ; SRTDRV ; This is the main routine for producing sorted listings. It sets ;004 ; up the sort index (after allocating memory for it), calls SORT ;004 ; if neccessary, and then lists the directory through the use of OUTBLK.;004 ; A sort is unneccessary if by position, since RT-11 directories ;004 ; are contiguous and ordered. SORT always sorts in ascending order; ;004 ; if we are doing a listing in reverse, we invert the index in place ;004 ; after the sort to reverse the order. ;004 ; ; Upon entry, FREEST points to the first sort block and ;004 ; FREEPT points past the last. The sort index is built ;004 ; past the last sort block, starting at FREEPT=INDST and ;004 ; running through INDEND ;004 ; ;- XTERNL GBLDAT GBLDAT ;004 GBLDAT ;MG01 SRTDRV:: MOV SBCNT,R2 ;Get the number of files ;004 BEQ 10$ ;Branch if none there ;004 ASL R2 ;Need SBCNT words for the index table ;004 MOV INDST,R0 ;Starting at end of sort entries ;004 CALL SRTMEM ;Request the memory ;004 MOV R2,INDEND ;INDEND points past end of index ;004 MOV FREEST,R1 ;First entry of index table ;004 ; is the first sort block ;004 101$: MOV R1,(R0)+ ;Move it in ;004 ADD #SBLKSZ,R1 ;Point to next sort block ;004 CMP R0,R2 ;Are we at end of index table? ;004 BNE 101$ ;No, do it again. ;004 CMP SWS,SPOS ;Sorting on position? ;004 BEQ 2$ ;Branch if so. No need to sort ;004 1$: CMP #1,SBCNT ;Only one file? ;CG04 BEQ 2$ ;Branch if so. No need to sort ;CG04 CALL SORT ;Go sort the entries 2$: TST SWR ;Does she want a reverse sort? ;004 BEQ 210$ ;No, skip reversal of index table ;004 MOV INDST,R2 ;Get the limits of ;004 MOV INDEND,R1 ; the index table ;004 204$: MOV (R2),R0 ;Isn't this just beautiful? ;004 MOV -(R1),(R2)+ ;swap entries in the index table ;004 MOV R0,(R1) ;working both forwards and backward ;004 CMP R2,R1 ;and keep it up until the ;004 BLO 204$ ;pointers cross each other ;004 210$: MOV SBCNT,R0 ;Get the number of files ;CG08 MOV SWC,R2 ;Get number of columns CMP #1,R2 ;Listing on one column? BNE 3$ ;Branch if not MOV INDST,R4 ;Point R4 at first index entry ;004 MOV #2,INK ;Set up the increment ;004 BR 9$ ;Go print the entries 3$: CALL DDIV ;Divide R0 by R2 MOV R0,QUO ; to get number of files per column MOV R1,REM ; and the number of leftovers CLR INK ;Clear the increment 4$: ADD #2,INK ;Bump the increment ;004 DEC R0 ;Decrement count BGE 4$ ;Loop MOV INDST,R0 ;R0 => first entry in index table ;004 MOV QUO,R3 ;Get number of lines we'll print BEQ 8$ ;Branch if # of entries < # of columns 5$: MOV R0,R4 ;R4 => first index to print on this line;004 MOV REM,R2 ;R2 = # of extra entries MOV SWC,R5 ;R5 = # of columns 6$: CALL OUTBLK ;Print an entry ADD INK,R4 ;Bump the entry pointer DEC R2 ;Decrement the counter BGE 7$ ;Branch if increment was correct SUB #2,R4 ;Else back up an entry ;004 7$: DEC R5 ;Decrement the column counter BNE 6$ ;Branch if more to come ADD #2,R0 ;Bump this pointer ;004 DEC R3 ;Decrement the line counter BNE 5$ ; and loop until done 8$: MOV REM,R0 ;Get # of extra entries BEQ 10$ ;Branch if none MOV INDST,R4 ;Point to 1st entry ADD INK,R4 ;Point to 2nd printed entry SUB #2,R4 ;Point to 1st non-printed entry ;004 9$: CALL OUTBLK ;Print it ADD INK,R4 ;Point to next entry DEC R0 ;Decrement the count BNE 9$ ; and loop until done 10$: RETURN .SBTTL SORT- Sort the directory entries ;+ ; ; SORT ; This routine sorts the sort-block entries. It is a indexed heap ;004 ; sort. The sort table entries remain fixed in memory, but the ;004 ; index to them is rearranged to put them in ascending order. ;004 ; All registers may be (and are) used. ;004 ; ;- GBLDAT ;004 SORT:: MOV INDEND,R3 ;Let R3 point past last index ;004 MOV R3,R4 ;Make an extra copy ;004 TST -(R4) ;R4=IR=last element ;004 MOV INDST,R2 ;Let R2 point to first index ;004 ;It will remain pointing here throughout;004 ; most of sort, as this is often used ;004 SUB R2,R3 ;Subtract to get 2*number of indices ;004 ASR R3 ;divide by 2 to get number of indices ;004 BIC #1,R3 ;chop off odd bit ;004 ADD R2,R3 ;Now R3 points one past halfway index ;004 ;004 ;R3 will be decremented down towards the first index during the ;004 ;heap creation phase. Once it reaches the first index, R4 will be ;004 ;decremented down to first index during the heap selection phase. ;004 ;004 10$: CMP R3,R2 ;Are we still in creation phase? ;004 BLOS 11$ ;Skip if we aren't ;004 MOV -(R3),R5 ;Decrement R3, get new hiree ;004 BR 12$ ;004 11$: ;We're in selection phase ;004 MOV (R4),R5 ;Clear space at end of array ;004 MOV (R2),(R4) ;Put top of heap into it ;004 TST -(R4) ;Decrease size of heap ;004 CMP R4,R2 ;Did we do the last selection? ;004 BNE 12$ ;No, more to do... ;004 MOV R5,(R2) ;We're done - save lowest of heap ;004 RETURN ;And return ;004 12$: ;Whether creating or selecting, we ;004 ;now sift R5 down to its proper level ;004 MOV R3,R1 ;004 MOV R3,-(SP) ;Save on stack for later use ;004 SUB R2,R3 ;004 ADD (SP),R3 ;004 TST (R3)+ ;Have R3 point twice as high as present ;004 MOV R2,-(SP) ;Save R2, we'll need it for compares ;004 20$: CMP R3,R4 ;While R3 less than or equal to R4 ;004 BHI 27$ ; (branch out if greater than) ;004 BEQ 22$ ;Skip if not a better underling ;004 MOV (R3)+,R0 ;Compare with better underling ;004 MOV (R3),R2 ; ;004 CMP (R0)+,(R2)+ ;Compare up to 5 words ;004 BLO 22$ ;004 BNE 21$ ;004 CMP (R0)+,(R2)+ ;004 BLO 22$ ;004 BNE 21$ ;004 CMP (R0)+,(R2)+ ;004 BLO 22$ ;004 BNE 21$ ;004 CMP (R0)+,(R2)+ ;004 BLO 22$ ;004 BNE 21$ ;004 CMP (R0)+,(R2)+ ;004 BLO 22$ ;004 21$: TST -(R3) ;Shouldn't have promoted; bring back ;004 22$: MOV R5,R0 ;Compare element pointed to by R5 ;004 MOV (R3),R2 ;004 CMP (R0)+,(R2)+ ;compare up to 5 words ;004 BHI 24$ ;004 BNE 23$ ;004 CMP (R0)+,(R2)+ ;004 BHI 24$ ;004 BNE 23$ ;004 CMP (R0)+,(R2)+ ;004 BHI 24$ ;004 BNE 23$ ;004 CMP (R0)+,(R2)+ ;004 BHI 24$ ;004 BNE 23$ ;004 CMP (R0)+,(R2)+ ;004 BHIS 24$ ;004 23$: MOV (R3),(R1) ;Demote R5 ;004 MOV R3,R1 ;004 SUB (SP),R3 ;004 ADD R1,R3 ;004 TST (R3)+ ;004 BR 20$ ;004 24$: MOV R4,R3 ;This was R5's level ;004 TST (R3)+ ;Set R3 to terminate sift-down ;004 BR 20$ ;004 27$: MOV (SP)+,R2 ;get back the first index ;004 MOV R5,(R1) ;Put R5 in his slot ;004 MOV (SP)+,R3 ;Get back our copy of R3 ;004 BR 10$ ;and loop around ;004 .SBTTL OUTBLK- Output a sort block ;+ ; ; OUTBLK ; This routine turns a sort block entry into a pseudo-directory entry ; and calls OUTFIL to send it to the listing file. Apparently ;004 ; OUTFIL only looks at the status, size, and date from the ;004 ; directory entry. The name and type go in through CHARS and ;004 ; the position goes in through SBLOCK. ;004 ; INPUTS: ;004 ; R4 -> Index to Sort block ;004 ; OUTPUTS: ;004 ; R1 is modified ;004 ; The filename is stored (in ASCII) in CHARS ;004 ; ;- XTERNL GBLDAT GBLDAT OUTBLK:: .SAVRG MOV R0,-(SP) ;Save R0 MOV (R4),R5 ;R5 -> Sort block ;004 MOV #DIRDUM,R0 ;R0 -> Temp directory entry ;004 3$: MOV #SRTORD,R2 ;Look through sort order table ;004 31$: CMP (R2)+,SWS ;until we find the right sort type ;004 BEQ 4$ ;branch if right type ;004 ADD #,R2 ;otherwise go to next type ;004 BR 31$ ;and try again ;004 4$: MOV #SBLKSZ/2,R1 ;Loop over each word in sort block ;004 MOVB (R2)+,R4 ;Last R4 words must be neg. if /REV ;004 41$: MOVB (R2)+,R3 ; Find the target word ;004 ADD R0,R3 ; in the directory entry ;004 MOV (R5)+,(R3) ; and move this sb word into de word ;004 TST SWR ;are we /REV? ;004 BEQ 42$ ;No, skip negatization ;004 CMP R1,R4 ;Is this a word to be negatized? ;004 BHI 42$ ;No, skip negatization ;004 COM (R3) ;Negatize it. ;004 42$: SOB R1,41$ ;Until we're at end of sort block ;004 MOV DE.DAT(R3),R1 ;Get the rationalized date word ;004 MOV R1,R2 ;make a second copy ;004 BIC #^c140000,DE.DAT(R3);only epoch bits in right place ;004 BIC #^c037000,R1 ;Get the year bits ;004 ASR R1 ; and put them ;004 SWAB R1 ; where RT-11 likes them ;004 BIC #^c000777,R2 ;Get the month and day bits ;004 ASL R2 ;shift them left to where ;004 ASL R2 ;RT-11 likes them ;004 ASL R2 ;004 ASL R2 ;004 ASL R2 ;004 ADD R2,R1 ;Add them onto year bits ;004 ADD R1,DE.DAT(R3) ;and onto epoch bits ;004 MOV R0,R5 ;OUTFIL wants R5 to point to dir ent ;004 TST (R0)+ ;R0 -> Filename ;CG08 100$: MOV #CHARS,R1 ;Store it in CHARS CALL RTOA ;Convert it to ASCII (OUTFIL expects it so) 600$: MOV DE.STR(R5),SBLOCK ;Get the starting block ;004 CALL OUTFIL ;Output the filename MOV (SP)+,R0 ;Restore R0 RETURN .SBTTL SAVBLK- Save information for the sort ;+ ; ; SAVBLK ; This routine saves the information needed by the sort in a sort block ; entry in free core. If it runs out of memory below the USR, it requests ; all available memory. The words in the directory entry are rearranged;004 ; according to the sort type being done and stored in the sort block. ;004 ; INPUTS: ; R5 -> directory entry ; OUTPUTS: ; R0 is modified ; ;- GBLDAT GBLDAT SAVBLK:: .SAVRG ;Save registers 2-5 ;004 MOV R1,-(SP) ;Save register 1 ;004 MOV FREEPT,R0 ;Get the pointer to free core MOV #SBLKSZ,R2 ;Get the number of bytes we need ;004 CALL SRTMEM ;Request more memory ;004 MOV R2,FREEPT ;R2 points to end of block we req ;004 2$: MOV SBLOCK,DE.STR(R5) ;Save the starting block ;004 BIT #,(R5) ;Empty entry? ;004 BEQ 21$ ;Branch if not ;004 CLR DE.FN1(R5) ;Else clear the filename for sort ;004 CLR DE.FN2(R5) ; both words ;004 CLR DE.TYP(R5) ; and the type ;004 CLR DE.DAT(R5) ; and clear the date for sort ;004 21$: MOV DE.DAT(R5),R1 ;Fix the date, now in DE.DAT(R0) ;004 MOV R1,R2 ;make a second copies of it ;004 BIC #^c140000,DE.DAT(R5) ;pick out the epoch bits ;004 BIC #^c000037,R1 ;pick out the year bits ;004 SWAB R1 ;put them in ;004 ASL R1 ; the right place ;004 BIC #^c037740,R2 ;pick out the month and day bits ;004 ASR R2 ;shift them five to the right... ;004 ASR R2 ;004 ASR R2 ;004 ASR R2 ;004 ASR R2 ;004 ADD R2,R1 ;And tack them on ;004 ADD R1,DE.DAT(R5) ;save the whole bunch ;004 3$: MOV #SRTORD,R2 ;Look through sort order table ;004 31$: CMP (R2)+,SWS ;until we find the right sort type ;004 BEQ 4$ ;branch if right type ;004 ADD #,R2 ;otherwise go to next type ;004 BR 31$ ;and try again ;004 4$: MOV #SBLKSZ/2,R4 ;Loop over each word in sort block ;004 MOVB (R2)+,R1 ;last R1 words to be neg if /REV ;004 41$: MOVB (R2)+,R3 ; Find the corresponding word ;004 ADD R5,R3 ; in the directory entry ;004 MOV (R3),(R0)+ ; and move it into the sort block ;004 TST SWR ;Are we reverse? ;004 BEQ 42$ ;No, don't worry about negatizing ;004 CMP R4,R1 ;Is this a word to be negatized? ;004 BHI 42$ ;No, skip it ;004 COM -2(R0) ;Negatize it ;004 42$: SOB R4,41$ ;Until we're at end of sort block ;004 INC SBCNT ;Bump the number of blocks to sort ;CG08 MOV (SP)+,R1 ;Restore R1 RETURN .SBTTL SRTMEM- Request memory for the sort ;004 ;+ ;004 ; ;004 ; SRTMEM ;004 ; This routine requests additional memory ;004 ; in free core. If it runs out of memory below the USR, it requests ;004 ; all available memory. If this fails, we bail out with an error. ;004 ; INPUTS: ;004 ; R0 -> where we are requesting memory ;004 ; R2 is how many bytes we request ;004 ; OUTPUTS: ;004 ; R0 is unmodified ;004 ; R2 points past end of just requested block ;004 ; ;004 ;- ;004 SRTMEM::ADD R0,R2 ;Point to the end of requested block ;004 CMP R2,FREEND ;Enough memory? ;004 BLOS 2$ ;Branch if so ;004 TST CORE ;Is there any more available? ;004 BEQ 1$ ;Branch if so... there may be ;004 ;+ ;004 ;ERROR ;004 $ERROR NOM,LEVEL=FATAL,RETURN=NO ;004 ;- ;004 ;004 1$: MOV R0,-(SP) ;Save the requested start ;004 .SETTOP #-2 ;Ask for all available memory ;004 MOV R0,FREEND ;Save what we got ;004 MOV (SP)+,R0 ;get back the requested start ;004 MOV SP,CORE ;Mark "no more core" ;004 BR SAVBLK ; and try again ;004 ;004 2$: RETURN ;004 .END