; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Sort directory

; In    r1 -> dirviewer block (strange)
;       [r1, #d_viewmode] :SHR: dbb_sortmode =
;         0 (name), 1 (type), 2 (size), 3 (date)

; Out   items re-ordered (blocks only - names are ref by ptrs)

SortDir Entry   "r1-r11"

 [ debug
 DREG r1, "Sorting dirviewer "
 ]
        InvSmiWidth  r1
        LDR     r0, [r1, #d_nfiles]
        CMP     r0, #2
        EXIT    LT                      ; [nothing to do]

        ; Check if there's room in sortingbuffer
        ADR     r10, sortingbuffer      ; r10 -> buffer
        CMP     r0, #sortingbuffer_entries
        BLT     %FT01

        ; If not, try and claim enough memory in RMA
        MOV     r3, r0, LSL #2          ; we want entries * 4 bytes
        MOV     r0, #ModHandReason_Claim
        SWI     XOS_Module
        EXIT    VS                      ; Couldn't claim it
        MOV     r10, r2                 ; r10 -> buffer

; work out correct sorting procedure for HeapSort, and do it!
01
        LDRB    r0, [r1, #d_viewmode]
        TST     r0, #db_sortorder
        ADREQ   r14, sortproctable
        ADRNE   r14, reversesortproctable

        AND     r0, r0, #db_sortmode
        MOV     r0, r0, LSR #dbb_sortmode ; 0..3
 [ debug
 DREG r0, "sort mode (0..3) "
 ]
        LDR     r2, [r14, r0, LSL #2]   ; offset to routine
        ADD     r2, r14, r2             ; r2 -> routine for OS_HeapSort

        LDR     r0, [r1, #d_nfiles]     ; r0 = number of items

        MOVEQ   r3, r1                  ; r3 -> dirviewer^ passed in r12 to sort procs
        ORRNE   r3, r1, #1              ; remember reverse sorts

        ADD     r4, r1, #d_headersize   ; r4 -> base of data
        MOV     r5, #df_size            ; r5 = element size
        MOV     r1, r10                 ; r1 -> array of pointers
 [ debug
 DREG r0,"OS_HeapSort: n ",cc,Integer
 DREG r1,", array ",cc
 DREG r2,", proc ",cc
 DREG r3,", baseaddr ",cc
 DREG r4,", block ",cc
 DREG r5,", size "
 ]
        TST     r1, #2_111 :SHL: 29     ; use old or new SWI depending on
        BNE     %FT20                   ; address
        ORR     r1, r1, #2_11 :SHL: 30  ; Ask HeapSort to build pointer array
                                        ; itself and shuffle data after sorting
        SWI     XOS_HeapSort
        B       %FT25
20      MOV     r7, #2_11 :SHL: 30
        SWI     XOS_HeapSort32
25
        ; if we claimed any RMA for the sort, free it now
        ADR     r0, sortingbuffer
        CMP     r0, r10
        EXIT    EQ                      ; We used sortingbuffer, not RMA

        MOV     r0, #ModHandReason_Free
        MOV     r2, r10
        SWI     XOS_Module
        EXIT

sortproctable

        DCD     sort_name - sortproctable ; directory viewer
        DCD     sort_type - sortproctable
        DCD     sort_size - sortproctable
        DCD     sort_date - sortproctable

reversesortproctable

        DCD     reverse_sort_name - reversesortproctable ; directory viewer
        DCD     reverse_sort_type - reversesortproctable
        DCD     reverse_sort_size - reversesortproctable
        DCD     reverse_sort_date - reversesortproctable

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Sort procedures called in SVC mode, with r13 FD stack

; In    r0 -> first object
;       r1 -> second object
;       r12 -> value from r3 on calling OS_HeapSort

; Out   LT,GE from CMP between first and second objects
;       r0-r3 may be corrupted
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; sort by name:
; -------------
;   names (A..Z)

reverse_sort_name

sort_name Entry
        TST     r12, #1                 ; NE = reverse sorting
        BIC     r3, r12, #3             ; zap flags, get back dirviewer^
        LDR     r3, [r3, #d_filenames]  ; base of filenames

        LDR     r2, [r1, #df_fileptr]
 [ not_16bit_offsets
        ADD     r2, r3, r2              ; r2 -> name(r1)
 |
        ADD     r2, r3, r2, LSR #16     ; r2 -> name(r1)
 ]

        LDR     r1, [r0, #df_fileptr]
 [ not_16bit_offsets
        ADD     r1, r3, r1              ; r1 -> name(r0)
 |
        ADD     r1, r3, r1, LSR #16     ; r1 -> name(r0)
 ]

        MOVNE   r3, r1                  ; swap r1 & r2 if reverse sort
        MOVNE   r1, r2
        MOVNE   r2, r3

        MOV     r0, #-1                 ; use configured territory
        MOV     r3, #1
        SWI     XTerritory_Collate
        EXIT    VS
        CMP     r0, #0                  ; set LT, GE depending on which is smaller
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; sort by type:
; -------------
;   untyped files
;   typed files (000..FFF)
;   applications
;   directories

        MACRO
$label  LType   $rd, $rs, $rtemp
$label  LDRB    $rtemp, [$rs, #df_type]
        CMP     $rtemp, #dft_applic
        MOVEQ   $rd, #&1000             ; applications next to last in list
        MOVNE   $rd, #&2000             ; dirs last in list

        CMP     $rtemp, #dft_file
      [ version >= 143
        CMPNE   $rtemp, #dft_partition
      ]
        BNE     %FT01

 ASSERT df_load = 0
 ASSERT df_exec = 4
 ASSERT $rd < $rtemp ; For LDMIA !!!
        LDMIA   $rs, {$rd, $rtemp}

        TEQ     $rd, $rtemp
        MOVEQ   $rd, #-1
        BEQ     %FT01

        CMN     $rd, #&00100000
        MOVCC   $rd, #-1                ; [undated; first in list]
        MOVCS   $rd, $rd, LSL #12
        MOVCS   $rd, $rd, LSR #20
01
        MEND

reverse_sort_type Entry

        LType   r3, r0, r14
        LType   r2, r1, r14
        B       %FT10

sort_type ALTENTRY

        LType   r2, r0, r14
        LType   r3, r1, r14
10
        CMP     r2, r3
        BLEQ    sort_name               ; sort by name if types equal
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; sort by size:
; -------------
;   files (large..0)
;   applications        full size not known, so can't really order by it
;   directories         ditto

        MACRO
$label  LSize   $rdlo, $rdhi, $rs
$label  LDRB    $rdlo, [$rs, #df_type]
 ASSERT dft_dir < dft_applic
 ASSERT dft_file < dft_dir
      [ version >= 143
        TEQ     $rdlo, #dft_partition
        MOVEQ   $rdlo, #dft_dir         ; equate partitions to dirs
      ]
        SUBS    $rdhi, $rdlo, #dft_dir  ; = 0 => 0 = dirs lowest
        MOVGT   $rdhi, #1               ; > 0 => 1 = applications next
        MOVMI   $rdhi, #2               ; < 0 => 2 = files highest
        MOVGE   $rdlo, #0               ; >=0 => apps & dirs have zero size
        LDRMI   $rdlo, [$rs, #df_length]
        MEND

reverse_sort_size Entry "r4, r5"

        LSize   r3, r5, r0
        LSize   r2, r4, r1
        B       %FT10

sort_size ALTENTRY

        LSize   r2, r4, r0
        LSize   r3, r5, r1
10
        SUBS    r14, r3, r2             ; descending order - CMP64
        MOVNE   r14, #Z_bit
        SBCS    r2, r5, r4
      [ No32bitCode
        TEQEQP  r14, pc
      |
        MRSEQ   r4, CPSR
        EOREQ   r4, r4, r14
        MSREQ   CPSR_f, r4
      ]
        BLEQ    sort_name               ; NB. don't corrupt r0,r1 if going
        EXIT                            ; to do sort_name !

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; sort by date:
; -------------
;   objects (new..1900)
;
; NB. Getting signed CMP results was difficult

        MACRO
$label  LDate   $rdlo, $rdhi, $rs
$label  LDRB    $rdhi, [$rs, #df_load]  ; High byte of date
        LDR     $rdlo, [$rs, #df_exec]  ; Low word of date
        MEND

reverse_sort_date Entry "r4, r5"

        LDate   r3, r5, r0              ; Get date
        LDate   r2, r4, r1
        B       %FT10

sort_date ALTENTRY

        LDate   r2, r4, r0              ; Get date
        LDate   r3, r5, r1
10
        SUBS    r14, r3, r2             ; descending order - CMP64
        MOVNE   r14, #Z_bit
        SBCS    r2, r5, r4
      [ No32bitCode
        TEQEQP  r14, pc
      |
        MRSEQ   r4, CPSR
        EOREQ   r4, r4, r14
        MSREQ   CPSR_f, r4
      ]
        BLEQ    sort_name               ; NB. don't corrupt r0,r1 if going
        EXIT                            ; to do sort_name !

        END