TITLE   'IN MEMORY SHELL-metzner sort'
sbttl   'from KILOBAUD april 1981 p164'
;
remark  'For fixed length records stored in memory
       Put no. of records in n1 and m1. The length
       of each record is stored at k1, and the starting
       address at j1. Start sort by calling location
       "entry". To change to descending sort change the
       instruction at neq: to DAH.'
;
n1:     .word   0       ; number of records
m1:     .word   0       ; ..same here
k1:     .word   0       ; length of records
j1:     .word   0       ; starting address of strings
i1:     .word   0       ; ptr
ml1:    .word   0       ; ptr
dj1:    .word   0       ; ptr
di1:    .word   0       ;ptr
;
entry:  lhld    j1      ; get start address
       push    h       ; ..save
       lhld    k1      ; get length
       push    h       ; ..it too
div:    xra     a       ; m1=m1/2
       lhld    m1
       mov     a,h
       rar
       mov     h,a
       mov     a,l
       rar
       mov     l,a
       shld    m1      ; save new m1
;
       ora     h       ; check if done
       jnz     ndon
       pop     b       ; finished
       pop     d       ; ..so return
       ret             ; ...now
;
;       set k1=n1-m1
;
ndon:   xchg            ; m1 to de
       lhld    n1
       mov     a,l
       sub     e
       mov     l,a
       mov     a,h
       sbb     d
       mov     h,a
       shld    k1
       lxi     h,1     ; set and save i=j=1
       shld    j1
       shld    i1
;
;       calc & save addr offset = m1*i1
;
       dcr     l
       pop     b       ; length of str=i1
       push    b       ; ..put it back
lp1:    dad     d
       dcx     b
       mov     a,b
       ora     c
       jnz     lp1
       shld    ml1
;
       xchg            ; calc & save d(j), d(i), d(i+m)
       pop     b
       pop     h
       push    h
       push    b
lp2:    shld    dj1
       shld    di1
       xchg
       dad     d
       xchg            ; HL has d(i), DE has d(i+m)
;
;       compare strings and switch
;
cp1:    pop     b       ; len of string=l1
       push    b
lp3:    ldax    d       ; compare each byte
       sub     m
       jnz     neq     ; not equal
       inx     h       ; if =, then next byte
       inx     d
       dcx     b
       mov     a,b
       ora     c
       jnz     lp3
       jmp     nsw     ; if done, don't switch
;
;       change next instruction to jc for descending
;
neq:    jnc     nsw     ; if d(i)<d(i+m) don't switch
;
sw:     push    b       ; switch bytes not equal
       mov     b,m
       ldax    d
       mov     m,a
       mov     a,b
       stax    d
       inx     h
       inx     d
       pop     b
       dcx     b
       mov     a,b
       ora     c
       jnz     sw
;
;       strings switched, chk if i1-m1 < 1
;
       lhld    m1
       mov     a,h
       cma
       mov     d,a
       mov     a,l
       cma
       mov     e,a
       lhld    i1
       dad     d       ; if i1-m1<1 then jump to same as
                       ; ..no switch
       jnc     nsw
;
;       calc new d(i), d(i+m)
;
       inx     h       ; save  new i1=i1-m
       shld    i1
       lhld    di1     ; old d(i)=new d(i+m)
       xchg
       lhld    ml1     ; address offset
       mov     a,e     ; new d(i)=old d(i)-offset
       sub     l
       mov     l,a
       mov     a,d
       sbb     h
       mov     h,a
       shld    di1     ; save new d(i)
       jmp     cp1     ; goto compare strings
;
;       check for j>k
;
nsw:    lhld    j1
       inx     h       ; save new j=old j+1
       shld    j1
       shld    i1
       xchg
       lhld    k1
       mov     a,l
       sub     e
       mov     a,h
       sbb     d
       jc      div     ; if j>k goto beginning and
                       ; ..divide m1
;
;       calc new d(j), d(i)
;
       lhld    dj1
       pop     d
       push    d
       dad     d       ; new d(j)=old d(j+1)
       xchg
       lhld    ml1
       xchg
       jmp     lp2
;
; that all folks
;
       .end    entry