    page    96,132
;§∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞§
;§                                                                          §
;§              ディレクトリエントリ  ソート  ユーティリティ                §
;§                                                                          §
;§                                     ＤＳＯＲＴ．ＥＸＥ  Ｖｅｒ１.１１    §
;§                                                                          §
;§                   Copyright (C) by 福地 邦雄 1991. All rights reserved.  §
;§∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞§
    .MODEL  SMALL,C
;
    DPB struc
drivenumber     db      ?       ;ドライブ番号
unitnumber      db      ?       ;ユニット番号
sectorlength    dw      ?       ;セクタ長
sectorperalloc  db      ?       ;１クラスタ当たりのセクタ数−１
shiftcount      db      ?       ;１クラスタ当たりのセクタ数の２のべき乗
reservedsector  dw      ?       ;先頭のリザーブセクタ数
numberoffat     db      ?       ;ＦＡＴ数
directoryentry  dw      ?       ;ルートディレクトリのエントリ数
datastartsector dw      ?       ;データ領域開始セクタ番号
datasector      dw      ?       ;最大クラスタ数（全クラスタ数＋１）
fatsector       db      ?       ;１ＦＡＴ当たりのセクタ数
directorystart  dw      ?       ;ディレクトリ領域開始セクタ番号
todeviceheader  dd      ?       ;デバイスヘッダへのポインタ
mediadescriptor db      ?       ;メディアディスクリプタ
diskchange      db      ?       ;ディスクの交換可能属性
tonextdpb       dd      ?       ;次のＤＰＢへのポインタ
currentcluster  dw      ?       ;カレントクラスタ
reserved        dw      ?       ;リザーブ
    DPB ends
;
YES     equ     1
NO      equ     0
FAT12   equ     0ff7h
FAT16   equ     0fff7h
direntrysize    equ 20h
;
    extrn   sweep:word,sortexec:word,recursive:word,dirgather:word
    extrn   dta:dword,srchname:dword,namebuff:dword,namebuffsiz:word
    extrn   dirtype:word,fattype:word,attribute:word,clustcount:word
    extrn   driveno:word,clustsize:word,fatsize:word,dirsize:word
    extrn   fatbuff:word,dirbuff:word,sortbuff:word,sortcount:word
    extrn   drvinf:byte,clustsect:word,sectcount:word,fatdrive:word
    extrn   sortfuncs:word,subchain:word,wildcard:byte,pathbuff:byte
    extrn   usagemsg:byte,entrycount:word,movecount:word,subsearch:word
    extrn   procs:byte,dirover:byte,fatover:byte,veralarm:byte,_vermsgsz:abs
    extrn   bothmsg:byte,sortmsg:byte,movemsg:byte,nothmsg:byte
    extrn   errorno:word,adjustroot:word
;
    extrn   getargs:near,options:near,usageout:near,abort:near,dosstdout:near
    extrn   dirlist:near,dirfind:near,strcopywild:near
    extrn   dosallocx:near,dirqsort:near,inttoasc0:near
;
    PUBLIC  main,sortproc,getdirinfo,getdpb,readdirectory,readrootdir
    PUBLIC  readfat,getfat12chain,getfat16chain,readsubdir,selection
    PUBLIC  remainsweep,copyback,filldeleted,writedirectory,checkrootsize
    PUBLIC  dspdirname,dspmsgend,altint23h,critical,breakflag,orgint23h
;
    .code
;
;------------------------------------------------------------------------------
;   書き込み時のCtrl+C押下によるディレクトリ破壊を防ぐ処理のワーク
;------------------------------------------------------------------------------
;
critical    dw  NO
breakflag   dw  NO
orgint23h   dd  0
prgname     db  'DirSort',0     ; これは別に意味なし
;
;------------------------------------------------------------------------------
;
;   main
;       ディレクトリエントリソートユーティリティ メインプログラム
;
;   dsort   <options>   directory name
;
;   IN      ds & es PSP セグメント
;   OUT     ?
;
;------------------------------------------------------------------------------
;
main        proc    near
;
    call    getargs                 ; コマンド行パラメータを引き数リストに変換
;   @if (zf,on)
      jnz   @i0001
        jmp     usageout            ; 引き数なしの時はヘルプメッセージ
;   @ifend
@i0001:
    push    ax
    mov     ax,_data                ; DS 設定
    mov     ds,ax
;
    mov     ah,30h                  ; DOS バージョンチェック
    int     21h
;   @if (al,>,3)                    ; 4.00 以上なら未サポート
      cmp   al,3
      jbe   @i0002
        mov     cx,word ptr _vermsgsz
        mov     dx,offset veralarm
        jmp     abort
;   @ifend
@i0002:
;
    mov     ax,1000h                ; ディレクトリ名バッファの獲得
    xor     dx,dx                   ; 4KB
    call    dosallocx
    mov     word ptr namebuff+2,ax
;
    mov     ax,3523h                ; Ctrl+C ベクタ取得
    int     21h
    mov     word ptr cs:orgint23h,bx
    mov     word ptr cs:orgint23h+2,es
    mov     bx,ds                   ; DS セーブ
    mov     es,bx
    mov     ax,2523h                ; Ctrl+C ベクタ置き換え
    mov     dx,offset altint23h     ;
    mov     bx,cs
    mov     ds,bx
    int     21h
    mov     bx,es                   ; DS リストア
    mov     ds,bx
    pop     ax
;
    call    options                 ; 引き数評価&対象ディレクトリリスト作成
;   @if (sortexec,/=,NO),or,(sweep,/=,NO)
      cmp   sortexec,NO
      jne   @i0003
      cmp   sweep,NO
      je    @i0004
@i0003:
;       @if (recursive,=,YES)       ; 再帰呼び出しをおこなうか？
          cmp   recursive,YES
          jne   @i0005
            mov     es,word ptr namebuff+2
            mov     bx,800h         ; ディレクトリ名バッファのサイズ変更
            mov     ah,4ah          ; 16KB
            int     21h
;           @if (cf,off)
              jc    @i0006
                add     namebuffsiz,7000h
;           @ifend
@i0006:
;       @ifend
@i0005:
        push    namebuffsiz         ; パラメータセット
        push    word ptr namebuff
        push    word ptr namebuff+2
        xor     ax,ax
        push    ax
        call    sortproc            ; ディレクトリソート実行
;   @ifend
@i0004:
;
    mov     ax,2523h                ; Ctrl+C ベクタ復元
    lds     dx,cs:orgint23h
    int     21h
;
    mov     ah,0dh              ; ディスクバッファ リセット
    int     21h
;
    mov     ax,4c00h                ; プログラム終了
    int     21h
;
main        endp
;
;------------------------------------------------------------------------------
;
;   sortproc
;       ディレクトリソートを実行する
;
;   TYPE    near call
;   IN      sp+2:ディレクトリ名リストアドレス
;           sp+6:ディレクトリ名バッファの空き領域の先頭
;           sp+8:ディレクトリ名バッファの空き領域サイズ
;   OUT     なし
;   保存レジスタ ds
;
;------------------------------------------------------------------------------
;
sortproc    proc    near    curnameoff,curnameseg,freenameoff,freenamesiz
;
    mov     di,curnameoff
    mov     es,curnameseg
;   @do until
@d0001:
        mov     entrycount,0        ; 処理したエントリのカウンタを初期化
        mov     sortcount,0
        mov     movecount,0
        mov     ah,0dh              ; ディスクバッファ リセット
        int     21h
;
        call    getdirinfo          ; ディレクトリ情報獲得
;       @if (zf,on),L
          jz    @i0007
          jmp   @i0008
@i0007:
            mov     di,curnameoff   ; ディレクトリ名表示
            mov     es,curnameseg
            call    dspdirname
            call    readdirectory   ; ディレクトリ読み込み
;           @if (zf,on)
              jnz   @i0009
;               @if (sortexec,=,YES),S
                  cmp   sortexec,YES
                  jne   @i0010
                    call    selection   ; ソート対象エントリ取り出し
;                   @if (ax,>,1)
                      cmp   ax,1
                      jbe   @i0011
                        push    ds
                        mov     ax,ds
                        mov     es,ax
                        mov     ax,offset sortfuncs
                        push    ax
                        push    sortcount
                        xor     ax,ax
                        push    ax
                        mov     ds,sortbuff
                        call    dirqsort    ; クイックソート
                        pop ds
;                   @ifend
@i0011:
;                   @if (sweep,=,YES)
                      cmp   sweep,YES
                      jne   @i0012
                        call    remainsweep ; ソート対象外エントリを掻き集める
;                   @ifend
@i0012:
                    call    copyback    ; ソートしたエントリを戻す
;               @else
                  jmp short @i0013
@i0010:
                    call    predelete
                    call    remainsweep
;               @ifend
@i0013:
                call    filldeleted     ; 削除エントリの情報をクリアする
                mov     cs:critical,YES ; クリティカルセクション開始
                call    writedirectory  ; ディレクトリ書き込み
                call    dspmsgend       ; 終了メッセージ表示
                mov     cs:critical,NO  ; クリティカルセクション終了
;               @if (cs:breakflag,=,YES)    ; Ctrl+Cが押下されたので終了
                  cmp   cs:breakflag,YES
                  jne   @i0014
                    mov     errorno,-1
                    xor     cx,cx
                    xor     dx,dx
                    jmp     abort
;               @ifend
@i0014:
;           @ifend
@i0009:
;           @if (recursive,=,YES)   ; 再帰呼び出し
              cmp   recursive,YES
              jne   @i0015
                mov     ah,0dh      ; ディスクバッファ リセット
                int     21h
;
                mov     subsearch,YES   ;
                mov     di,curnameoff   ; サブディレクトリのリスト獲得
                mov     es,curnameseg
                call    strcopywild
                mov     word ptr srchname,di
                mov     word ptr srchname+2,es
                call    dirlist
                mov     ax,word ptr namebuff
;               @if (ax,/=,freenameoff) ; サブディレクトリ有りの時
                  cmp   ax,freenameoff
                  je    @i0016
                    push    namebuffsiz
                    push    ax
                    push    word ptr namebuff+2
                    push    freenameoff
                    call    sortproc    ; ディレクトリソート再帰実行
;               @ifend
@i0016:
                mov     si,freenameoff  ; 各ワーク情報を再帰実行から戻す
                mov     es,freenamesiz
                mov     namebuffsiz,es
                mov     word ptr namebuff,si
                mov     es,curnameseg
                mov     word ptr es:[si],0
                mov     subsearch,NO    ;
;           @ifend
@i0015:
;       @ifend
@i0008:
        mov     di,curnameoff       ; 次の対象ディレクトリへ
        mov     es,curnameseg
        cld
        xor     ax,ax
        mov     cx,-1
      repne scasb
        mov     curnameoff,di
;   @doend (byte ptr es:[di],=,0),L ; ディレクトリリストの終了か？
      cmp   byte ptr es:[di],0
      je    @d0002
      jmp   @d0001
@d0002:
;
    ret     8
;
sortproc    endp
;
;------------------------------------------------------------------------------
;
;   getdirinfo
;       ディレクトリ及びその所属するドライブの情報を獲得する
;
;   TYPE    near call
;   IN      ds:di = ディレクトリ名
;   OUT     drvinf = DPBのコピー  その他 ディレクトリ情報
;   保存レジスタ bx,cx,dx,si,di,bp,ds,es
;
;------------------------------------------------------------------------------
;
getdirinfo  proc    near
;
    call    dirfind
;   @if (zf,on)
      jnz   @i0017
        mov     dirtype,ax          ; ディレクトリタイプ ルート/サブ
        mov     subchain,ax         ; ＦＡＴチェインの先頭
        mov     driveno,dx          ; ドライブ番号
        dec     driveno
;
        mov     di,offset drvinf    ; Drive Parameter Block 取得
        call    getdpb
;
;       @if (drvinf.datasector,<=,4086),S    ; 12bitFAT/16bitFAT
          cmp   drvinf.datasector,4086
          ja    @i0018
            mov     fattype,FAT12            ;   v1.00バグ '='が無かった
;       @else
          jmp short @i0019
@i0018:
            mov     fattype,FAT16
;       @ifend
@i0019:
        xor     ax,ax
        mov     al,drvinf.sectorperalloc
        inc     ax
        mov     clustsect,ax        ; １クラスタ当たりのセクタ数
        mul     drvinf.sectorlength
        mov     clustsize,ax        ; １クラスタのバイトサイズ
        xor     ax,ax
;   @ifend
@i0017:
    ret
;
getdirinfo  endp
;
;------------------------------------------------------------------------------
;
;   getdpb
;       ドライブパラメータブロックをコピーする
;
;   TYPE    near call
;   IN      dl = ドライブ番号 A:1 B:2 ...
;           ds:di = drive parameter block をコピーする領域のアドレス
;   OUT     ax = 完了コード
;   保存レジスタ bx,cx,dx,si,di,bp,ds,es
;
;------------------------------------------------------------------------------
;
getdpb      proc    near    uses bx cx si di ds es
;
    cld
    mov     ax,ds
    mov     es,ax
    mov     ah,32h                  ; DPBアドレス取得 非公開
    mov     cx,10h
    int     21h
;
    mov     si,bx
  rep   movsw                       ; DPB コピー
    ret
;
getdpb      endp
;
;------------------------------------------------------------------------------
;
;   readdirectory
;       ディレクトリを読み込む
;
;   TYPE    near call
;   IN      dirtype,driveno,drvinf構造体,fatdrive
;   OUT     ax = 完了コード     entrycount,clustcount
;   保存レジスタ bx,cx,dx,si,di,bp,ds,es
;
;------------------------------------------------------------------------------
;
readdirectory   proc    near
;
;   @if (dirtype,=,0),S             ; ルートディレクトリ
      cmp   dirtype,0
      jne   @i0020
        mov     ax,drvinf.directoryentry
;       @if (ax,<=,2048),S
          cmp   ax,2048
          ja    @i0021
            mov     entrycount,ax   ; ディレクトリエントリ数 格納
            mov     adjustroot,NO
            call    readrootdir
;       @else
          jmp short @i0022
@i0021:
            mov     entrycount,2048 ; ディレクトリエントリ数を2048とする
            mov     adjustroot,YES  ; ルートのエントリ数評価を遅らせる
            call    readrootdir
            call    checkrootsize   ; エントリ数評価
;           @if (zf,off)
              jz    @i0023
                mov     ah,9            ; ルートディレクトリサイズオーバー表示
                mov     dx,offset dirover
                int     21h
                mov     ax,-1
                jmp     rdirerror
;           @ifend
@i0023:
;       @ifend
@i0022:
;   @else
      jmp short @i0024
@i0020:
        mov     ax,driveno          ; サブディレクトリ
;       @if (ax,/=,fatdrive)        ; 読み込み済FATと違うドライブ名の時
          cmp   ax,fatdrive
          je    @i0025
            xor     ax,ax           ; FATサイズ計算
            mov     al,drvinf.fatsector
            mul     drvinf.sectorlength
;           @if (dx,=,1),and,(ax,=,0),or,(dx,=,0),S
              cmp   dx,1
              jne   @i0026
              or    ax,ax
              je    @i0027
@i0026:
              or    dx,dx
              jne   @i0028
@i0027:
                call    readfat     ; FAT読み込み
;           @else
              jmp short @i0029
@i0028:
                mov     ah,9        ; FATサイズオーバー表示
                mov     dx,offset fatover
                int     21h
                mov     ax,-1
                jmp     rdirerror
;           @ifend
@i0029:
;       @ifend
@i0025:
;
        cld                         ; サブディレクトリのクラスタチェインを獲得
        mov     di,offset subchain
        mov     es,fatbuff
;       @if (fattype,=,FAT12),S
          cmp   fattype,FAT12
          jne   @i0030
            call    getfat12chain
;       @else
          jmp short @i0031
@i0030:
            call    getfat16chain
;       @ifend
@i0031:
        mov     clustcount,dx       ; サブディレクトリのクラスタ数を設定
        mov     ax,dx
        mul     clustsize
        mov     cx,32               ; ディレクトリエントリ数 計算 格納
        div     cx
;       @if (ax,<=,2048),S
          cmp   ax,2048
          ja    @i0032
            mov     entrycount,ax
            call    readsubdir      ; サブディレクトリ読み込み
;       @else
          jmp short @i0033
@i0032:
            mov     ah,9            ; ディレクトリサイズオーバー表示
            mov     dx,offset dirover
            int     21h
            mov     ax,-1
;       @ifend
@i0033:
;   @ifend
@i0024:
rdirerror:
    test    ax,ax
    ret
;
readdirectory   endp
;
;------------------------------------------------------------------------------
;
;   readrootdir
;       ルートディレクトリの内容をメモリに読み込む
;
;   TYPE    near call
;   IN      drive parameter block 領域      adjustroot
;   OUT     dirbuff = 読み込んだディレクトリのセグメントアドレス
;   保存レジスタ bp,ds,es
;
;------------------------------------------------------------------------------
;
readrootdir     proc    near    uses bp
;
;   @if (adjustroot,=,NO),S
      cmp   adjustroot,NO
      jne   @i0034
        mov     ax,drvinf.datastartsector ; ディレクトリサイズ計算とメモリ獲得
        sub     ax,drvinf.directorystart
;   @else
      jmp short @i0035
@i0034:
        xor     ax,ax                     ; ルートディレクトリが2048を超えて
        mov     dx,1                      ; いる場合の暫定措置
        div     drvinf.sectorlength
;   @ifend
@i0035:
    mov     sectcount,ax
    mul     drvinf.sectorlength
    mov     dirsize,ax
    call    dosallocx
    mov     dirbuff,ax
;
    push    ds                      ; ルートディレクトリ読み込み
    mov     ax,driveno
    xor     bx,bx
    mov     cx,sectcount
    mov     dx,drvinf.directorystart
    mov     ds,dirbuff
    int     25h
;   @if (cf,on)
      jnc   @i0036
        xor     cx,cx
        xor     dx,dx
        jmp     abort
;   @ifend
@i0036:
    popf
    pop     ds
    xor     ax,ax
    ret
;
readrootdir     endp
;
;------------------------------------------------------------------------------
;
;   checkrootsize
;       ルートディレクトリのエントリ数をチェックする
;
;   TYPE    near call
;   IN      dirbuff = 読み込んだディレクトリのセグメントアドレス
;   OUT     ax = 0 ディレクトリ数が範囲内    ax /= 0 範囲オーバー
;   保存レジスタ bx,cx,dx,si,di,bp,ds,es
;
;------------------------------------------------------------------------------
;
checkrootsize   proc    near    uses di es
;
    xor     di,di                   ; オフセットを0
    mov     es,dirbuff              ; ディレクトリバッファセグメントを取得
;   @do until
@d0003:
;       @if (byte ptr es:[di],=,0)  ; 最終エントリを発見したかの判定
          cmp   byte ptr es:[di],0
          jne   @i0037
            xor     ax,ax           ; 有効+削除エントリが64KB未満(範囲内)
            jmp     chrtszfind
;       @ifend
@i0037:
        lea     di,[di+direntrysize] ; 次のエントリへ
;   @doend (di,=,0)                 ; 64KBひとまわりしたか？
      or    di,di
      jne   @d0003
    mov     ax,-1                   ; 扱える範囲を超えている
chrtszfind:
    test    ax,ax
    ret
;
checkrootsize   endp
;
;------------------------------------------------------------------------------
;
;   readfat
;       FATを読み込むための領域を獲得し、FATを読み込む
;
;   TYPE    near call
;   IN      drive parameter block 領域
;   OUT     fatbuff = 読み込んだFATのセグメントアドレス
;   保存レジスタ bp,ds,es
;
;------------------------------------------------------------------------------
;
readfat     proc    near    uses bp
;
;   @if (fatdrive,/=,-1)            ; 既に別のFATを読み込み済の時、解放する
      cmp   fatdrive,-1
      je    @i0038
        mov     es,fatbuff
        int     21h
        mov     fatdrive,-1
        mov     fatbuff,0
;   @ifend
@i0038:
    xor     ax,ax                   ; FAT用領域獲得
    mov     al,drvinf.fatsector
    mul     drvinf.sectorlength
    call    dosallocx
    mov     fatbuff,ax
;
    push    ds                      ; FAT読み込み
    mov     ax,driveno
    mov     fatdrive,ax
    xor     bx,bx
    xor     cx,cx
    mov     cl,drvinf.fatsector
    mov     dx,drvinf.reservedsector
    mov     ds,fatbuff
    int     25h
;   @if (cf,on)
      jnc   @i0039
        xor     cx,cx
        xor     dx,dx
        jmp     abort
;   @ifend
@i0039:
    popf
    pop     ds
    ret
;
readfat     endp
;
;------------------------------------------------------------------------------
;
;   getfat12chain
;       12ビットFATのチェインをたどって､配列に書き出す｡
;
;   TYPE    near call
;   IN      es:オフセット０= FAT領域
;           ds:di = FATチェインを書き出す配列､ 及びその先頭に最初のクラスタ
;           番号を格納しておくこと
;   OUT     dx = チェインの総クラスタ数
;   保存レジスタ si,bp,ds,es
;
;------------------------------------------------------------------------------
;
getfat12chain   proc    near
;
    mov     cl,4
    xor     dx,dx
;   @do while,(word ptr [di],<,FAT12)
@d0004:
      cmp   word ptr [di],FAT12
      jae   @d0005
        mov     bx,[di]
        mov     ax,bx
        shr     ax,1
        add     bx,ax
        mov     ax,es:[bx]
;       @if (word ptr [di],off,1),S
          test  word ptr [di],1
          jnz   @i0040
            and     ax,0fffh
;       @else
          jmp short @i0041
@i0040:
            shr     ax,cl
;       @ifend
@i0041:
        lea     di,[di+2]
        mov     [di],ax
        inc     dx
;   @doend
      jmp   @d0004
@d0005:
    ret
;
getfat12chain   endp
;
;------------------------------------------------------------------------------
;
;   getfat16chain
;       16ビットFATのチェインをたどって､配列に書き出す｡
;
;   TYPE    near call
;   IN      es:オフセット０ = FAT領域
;           ds:di = FATチェインを書き出す配列､ 及びその先頭に最初のクラスタ
;           番号を格納しておくこと
;   OUT     dx = チェインの総クラスタ数
;   保存レジスタ cx,si,bp,ds,es
;
;------------------------------------------------------------------------------
;
getfat16chain   proc    near
;
    xor     dx,dx
;   @do while,(word ptr [di],<,FAT16)
@d0006:
      cmp   word ptr [di],FAT16
      jae   @d0007
        mov     bx,[di]
        shl     bx,1
        mov     ax,es:[bx]
        lea     di,[di+2]
        mov     [di],ax
        inc     dx
;   @doend
      jmp   @d0006
@d0007:
    ret
;
getfat16chain   endp
;
;------------------------------------------------------------------------------
;
;   readsubdir
;       サブディレクトリを読み込む
;
;   TYPE    near call
;   IN      clustcount ディレクトリのクラスタ数
;   OUT     dirbuff = 読み込んだディレクトリのセグメントアドレス
;   保存レジスタ cx,si,bp,ds,es
;
;------------------------------------------------------------------------------
;
readsubdir  proc    near
    local cluster:word
;
    mov     dx,clustcount           ; ディレクトリサイズ計算
    mov     cluster,dx
    mov     ax,clustsect
    mul     dx
    mul     drvinf.sectorlength
    mov     dirsize,ax
    call    dosallocx               ; ディレクトリバッファ獲得
    mov     dirbuff,ax
    xor     bx,bx
    mov     di,offset subchain      ; ディレクトリクラスタチェインの先頭
;
    push    ds
    mov     ax,ds
    mov     es,ax
    mov     ds,dirbuff
;   @do until
@d0008:
        mov     ax,es:[di]          ; ディレクトリクラスタ読み込み
        sub     ax,2
        mov     cx,es:clustsect
        mul     cx
        add     ax,es:drvinf.datastartsector
        mov     dx,ax
        mov     ax,es:driveno
        push    bp
        push    di
        int     25h
;       @if (cf,on)
          jnc   @i0042
            xor     cx,cx
            xor     dx,dx
            jmp     abort
;       @ifend
@i0042:
        popf
        pop     di
        pop     bp
        add     bx,es:clustsize     ; 次のバッファオフセット
        lea     di,[di+2]           ; 次のクラスタ
        dec     cluster             ; カウントダウン
;   @doend (zf,on)
      jnz   @d0008
    pop ds
    xor     ax,ax
    ret
;
readsubdir  endp
;
;------------------------------------------------------------------------------
;
;   selection
;       読み込んだディレクトリからattributeで指定されたエントリを選択して
;       ソートバッファに移動する
;
;   TYPE    near call
;   IN      dirbuff = 読み込んだディレクトリのセグメントアドレス その他
;   OUT     sortbuff = ソート対象を選択･移動したセグメントアドレス
;   保存レジスタ bp,ds
;
;------------------------------------------------------------------------------
;
selection   proc    near
;
    mov     ax,dirsize              ; ディレクトリサイズからバッファサイズ
;   @if (ax,/=,0),S                 ; 64KB未満
      or    ax,ax
      je    @i0043
        xor     dx,dx
;   @else                           ; 64KB
      jmp short @i0044
@i0043:
        mov     dx,1
;   @ifend
@i0044:
    call    dosallocx               ; ソートバッファ獲得
    mov     sortbuff,ax
    mov     es,ax
    mov     bx,attribute            ; 選出属性
    mov     dx,entrycount           ; エントリ数
    xor     si,si
    xor     di,di
;   @if (dirtype,/=,0)              ; サブディレクトリの時は最初の２つを除外
      cmp   dirtype,0
      je    @i0045
        sub     dx,2
        mov     si,64
;   @ifend
@i0045:
;
    push    ds
    cld
    xor     ax,ax
    mov     ds,dirbuff
;   @do while,(dx,/=,0),and,(byte ptr [si],/=,0)
@d0009:
      or    dx,dx
      je    @d0010
      cmp   byte ptr [si],0
      je    @d0010
;       @cbegin
;       @case (byte ptr [si],=,0e5h),S  ; 削除エントリか？
          cmp   byte ptr [si],0e5h
          jne   @c0002
            mov     byte ptr [si],0     ; 後の処理のために0を書いておく
            lea     si,[si+20h]
;       @case (byte ptr [si+0bh],on,bl),S   ; 属性違いか？
          jmp short @c0001
@c0002:
          test  byte ptr [si+0bh],bl
          jz    @c0003
            lea     si,[si+20h]
;       @other                      ; ソートバッファへ移動
          jmp short @c0001
@c0003:
            mov     cx,10h
          rep   movsw
            mov     byte ptr [si-20h],0 ; 移動元に0を書いておく
;           @if (byte ptr [di-20h],=,5) ; 名前の頭がE5用のコードなら戻しておく
              cmp   byte ptr [di-20h],5
              jne   @i0046
                mov     byte ptr [di-20h],0e5h
;           @ifend
@i0046:
            inc     ax              ; 移動したエントリ数を加算
;       @cend
@c0001:
        dec     dx                  ; カウントダウン
;   @doend
      jmp   @d0009
@d0010:
    pop     ds
    mov     sortcount,ax            ; 移動したエントリ数を記録
    ret
;
selection   endp
;
;------------------------------------------------------------------------------
;
;   predelete
;       後のremainsweepルーチンのために削除エントリの先頭を00とする
;
;   TYPE    near call
;   IN      entrycount,dirbuff
;   OUT     なし
;   保存レジスタ ax,bx,dx,si,bp,ds
;
;------------------------------------------------------------------------------
;
predelete   proc    near
;
    mov     cx,entrycount
    xor     di,di
    mov     es,dirbuff
;   @do until
@d0011:
;       @if (byte ptr es:[di],=,0e5h)
          cmp   byte ptr es:[di],0e5h
          jne   @i0047
            mov     byte ptr es:[di],0
;       @ifend
@i0047:
        lea     di,[di+20h]
        dec     cx
;   @doend (zf,on)
      jnz   @d0011
    ret
;
predelete   endp
;
;------------------------------------------------------------------------------
;
;   remainsweep
;       ソート対象外のエントリをディレクトリバッファの先頭に集める
;
;   TYPE    near call
;   IN      entrycount,dirbuff
;   OUT     movecount
;   保存レジスタ ax,bp,ds
;
;------------------------------------------------------------------------------
;
remainsweep proc    near
;
    cld
    push    ds
    xor     bx,bx
    mov     dx,entrycount           ; ディレクトリのエントリサイズ
    mov     es,dirbuff
    mov     ds,dirbuff
    xor     di,di
;   @do while,(byte ptr [di],/=,0),and,(dx,/=,0) ; 最初の空きエントリ位置取得
@d0012:
      cmp   byte ptr [di],0
      je    @d0013
      or    dx,dx
      je    @d0013
        lea     di,[di+20h]
        dec     dx
;   @doend
      jmp   @d0012
@d0013:
    mov     si,di
;   @do until
@d0014:
;       @do while,(byte ptr [si],=,0),and,(dx,/=,0) ; 次の有効エントリ位置取得
@d0015:
          cmp   byte ptr [si],0
          jne   @d0016
          or    dx,dx
          je    @d0016
            lea     si,[si+20h]
            dec     dx
;       @doend
          jmp   @d0015
@d0016:
;       @if (dx,/=,0)               ; 終了でなければエントリを頭へ詰める
          or    dx,dx
          je    @i0048
            inc     bx
            mov     cx,10h
          rep   movsw
            mov     byte ptr [si-20h],0 ; 移動元を空きエントリとする
            dec     dx              ; カウントダウン
;           @do while,(byte ptr [di],/=,0)  ; 次の空きエントリ位置取得
@d0017:
              cmp   byte ptr [di],0
              je    @d0018
                lea     di,[di+20h]
;           @doend
              jmp   @d0017
@d0018:
;       @ifend
@i0048:
;   @doend (dx,=,0)
      or    dx,dx
      jne   @d0014
    pop     ds
    mov     movecount,bx            ; 移動したエントリ数を記録
    ret
;
remainsweep endp
;
;------------------------------------------------------------------------------
;
;   copyback
;       ソートバッファの内容をディレクトリバッファへ書き戻す
;
;   TYPE    near call
;   IN      sortcount,sortbuff,dirbuff
;   OUT     dirbuff
;   保存レジスタ    bx,bp,ds
;
;------------------------------------------------------------------------------
;
copyback    proc    near    uses ds
;
    cld
    mov     dx,sortcount            ; ソートバッファ上のエントリ数
    mov     es,dirbuff
    mov     ds,sortbuff
    xor     si,si
    xor     di,di
;   @do while,(dx,/=,0)
@d0019:
      or    dx,dx
      je    @d0020
;       @if (byte ptr es:[di],=,0),S    ; ディレクトリバッファは空きエントリ？
          cmp   byte ptr es:[di],0
          jne   @i0049
;           @if (byte ptr [si],=,0e5h)  ; 名前の頭がE5なら、変換しておく
              cmp   byte ptr [si],0e5h
              jne   @i0050
                mov     byte ptr [si],05h
;           @ifend
@i0050:
            mov     cx,10h          ; コピー
          rep   movsw
            dec     dx              ; カウントダウン
;       @else
          jmp short @i0051
@i0049:
            lea di,[di+20h]         ; 次のディレクトリバッファエントリへ
;       @ifend
@i0051:
;   @doend
      jmp   @d0019
@d0020:
;
    mov     ax,ds                   ; ソートバッファの解放
    mov     es,ax
    mov     ah,49h
    int     21h
;
    ret
;
copyback    endp
;
;------------------------------------------------------------------------------
;
;   filldeleted
;       ディレクトリ中の削除エントリをクリアする
;
;   TYPE    near call
;   IN      dirsize,dirbuff
;   OUT     なし
;   保存レジスタ    bx,dx,bp,ds
;
;------------------------------------------------------------------------------
;
filldeleted proc    near
;
    cld
    mov     ax,0f6h                 ; 埋め込みデータの設定 
    mov     si,dirsize              ; ディレクトリの最終ポイント取得
    mov     es,dirbuff
;   @do until
@d0021:
        lea     si,[si-20h]         ; 最終位置から先頭方向へ
;       @if (byte ptr es:[si],=,0),S    ; 削除エントリ判定
          cmp   byte ptr es:[si],0
          jne   @i0052
            mov     es:[si],ah      ; 頭1バイト 0orE5
            mov     cx,1fh          ; 残り31バイトをF6で埋める
            lea     di,[si+1]
          rep   stosb
;       @else                       ; 有効エントリが見つかったので
          jmp short @i0053
@i0052:
            mov     ah,0e5h         ; それ以後は頭1バイトをE5に変更
;       @ifend
@i0053:
;   @doend (si,=,0)                 ; ディレクトリ先頭になるまで
      or    si,si
      jne   @d0021
    ret
;
filldeleted endp
;
;------------------------------------------------------------------------------
;
;   writedirectory
;       ディレクトリバッファをファイルに書き戻す
;
;   TYPE    near call
;   IN      dirtype,driveno,drvinf構造体,sectcount,clustcount,dirbuff
;           clustsect,clustsize,subchain
;   OUT     なし
;   保存レジスタ
;
;------------------------------------------------------------------------------
;
writedirectory  proc    near
        local cluster:word
;
;   @if (dirtype,=,0),S
      cmp   dirtype,0
      jne   @i0054
        push    ds                  ; ルートディレクトリ書き込み
        mov     ax,driveno
        xor     bx,bx
        mov     cx,sectcount
        mov     dx,drvinf.directorystart
        mov     ds,dirbuff
        push    bp
        int     26h
;       @if (cf,on)
          jnc   @i0055
            xor     cx,cx
            xor     dx,dx
            jmp     abort
;       @ifend
@i0055:
        popf
        pop     bp
        pop     ds
;   @else
      jmp short @i0056
@i0054:
        push    ds                  ; サブディレクトリ書き込み
        mov     ax,clustcount
        mov     cluster,ax
        mov     di,offset subchain
        mov     ax,ds
        mov     es,ax
        xor     bx,bx
        mov     ds,dirbuff
;       @do until
@d0022:
            mov     ax,es:[di]
            sub     ax,2
            mov     cx,es:clustsect
            mul     cx
            add     ax,es:drvinf.datastartsector
            mov     dx,ax
            mov     ax,es:driveno
            push    bp
            push    di
            int     26h
;           @if (cf,on)
              jnc   @i0057
                xor     cx,cx
                xor     dx,dx
                jmp abort
;           @ifend
@i0057:
            popf
            pop     di
            pop     bp
            add     bx,es:clustsize
            lea     di,[di+2]
            dec     cluster
;       @doend (zf,on)
          jnz   @d0022
        pop     ds
;   @ifend
@i0056:
;
    mov     es,dirbuff              ; ソートバッファの開放
    mov     ah,49h
    int     21h
;
    ret
;
writedirectory  endp
;
;------------------------------------------------------------------------------
;
;   dspdirname
;       処理中ディレクトリ名を表示する
;
;   TYPE    near call
;   IN      ES:DI ディレクトリ名文字列アドレス
;   OUT     なし
;   保存レジスタ    DS
;
;------------------------------------------------------------------------------
;
dspdirname  proc
;
    mov     ah,9        ; 処理中メッセージ表示
    mov     dx,offset procs
    int     21h
;
    cld                             ; ディレクトリ名長さを獲得
    mov     cx,-1
    xor     ax,ax
    mov     dx,di
  repne     scasb
    not     cx
    dec     cx
;
    push    ds                      ; ディレクトリ名表示
    mov     ax,es
    mov     ds,ax
    call    dosstdout
    pop     ds
;
    mov     ah,2                ; 行頭への復帰
    mov     dl,0dh
    int     21h
;
    ret
;
dspdirname  endp
;
;------------------------------------------------------------------------------
;
;   dspmsgend
;       処理終了メッセージを表示する
;
;   TYPE    near call
;   IN      sortcount,movecount,sortproc,sweep
;   OUT     なし
;   保存レジスタ    ax,bx,cx,dx,si,di,bp,ds,es
;
;------------------------------------------------------------------------------
;
dspmsgend   proc    uses ax bx cx dx si di ds es
        local   wrks:dword,wrka:word
;
    mov     ax,sortcount            ; ソートしたエントリ数
    mov     bx,movecount            ; 移動したエントリ数
    mov     cx,ax
    add     cx,bx
;   @cbegin
;   @case (sortexec,=,YES),and,(sweep,=,YES),and,(cx,/=,0),S ; ソート&移動
      cmp   sortexec,YES
      jne   @c0005
      cmp   sweep,YES
      jne   @c0005
      or    cx,cx
      je    @c0005
        mov     ax,cx
        mov     si,offset bothmsg
;   @case (sortexec,=,YES),and,(sweep,=,NO),and,(ax,/=,0),S ; ソートのみ
      jmp short @c0004
@c0005:
      cmp   sortexec,YES
      jne   @c0006
      cmp   sweep,NO
      jne   @c0006
      or    ax,ax
      je    @c0006
;       @if (ax,>,1),S
          cmp   ax,1
          jbe   @i0058
            mov     si,offset sortmsg   ; 2つ以上ならソートのみ表示
;       @else
          jmp short @i0059
@i0058:
            mov     si,offset bothmsg   ; 1つだけならソート&移動表示
;       @ifend
@i0059:
;   @case (sortexec,=,NO),and,(sweep,=,YES),and,(bx,/=,0),S ; 移動のみ
      jmp short @c0004
@c0006:
      cmp   sortexec,NO
      jne   @c0007
      cmp   sweep,YES
      jne   @c0007
      or    bx,bx
      je    @c0007
        mov     ax,cx
        mov     si,offset movemsg   ; 移動
;   @other
      jmp short @c0004
@c0007:
        xor     ax,ax
        mov     si,offset nothmsg   ; 対象なし
;   @cend
@c0004:
;   @if (ax,/=,0)
      or    ax,ax
      je    @i0060
        mov     di,ss               ; 処理したエントリ数表示
        mov     es,di
        lea     di,offset wrka+1
        call    inttoasc0
        lea     di,[di-5]           ; 0サプレス処理
        push    di
        mov     cx,4
;       @do while,(byte ptr es:[di],=,'0'),and,(cx,/=,0)
@d0023:
          cmp   byte ptr es:[di],'0'
          jne   @d0024
          or    cx,cx
          je    @d0024
            mov     byte ptr es:[di],' '
            inc     di
            dec     cx
;       @doend
          jmp   @d0023
@d0024:
        mov     cx,5                ; エントリ数表示
        pop     dx
        mov     di,ds
        push    ss
        pop     ds
        call    dosstdout
        mov     ds,di
;   @ifend
@i0060:
    mov     ah,9                    ; エントリ数に続くメッセージ表示
    mov     dx,si
    int     21h
    ret
;
dspmsgend   endp
;
;------------------------------------------------------------------------------
;
;   altint23h
;       Ctrl+C押下の横取り
;
;   TYPE    interrupt
;   IN      なし
;   OUT     なし
;   保存レジスタ    ax,bx,cx,dx,si,di,bp,ds,es
;
;------------------------------------------------------------------------------
;
altint23h   proc
;
;   @if (cs:critical,=,NO),S        ; クリティカルセクションではない時
      cmp   cs:critical,NO
      jne   @i0061
        jmp     cs:orgint23h        ; 既存の終了処理へ
;   @else                           ; クリティカルセクションの時
      jmp short @i0062
@i0061:
        mov     cs:breakflag,YES    ; Ctrl+C押下を記憶しただけで復帰
        iret
;   @ifend
@i0062:
;
altint23h   endp
;
        end     main
