home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol090 / sdir.mac < prev    next >
Encoding:
Text File  |  1984-04-29  |  32.1 KB  |  1,377 lines

  1. ;
  2. ; SYSLIB Module Name:  SDIR
  3. ; Author:  Richard Conn
  4. ; SYSLIB Version Number:  2.0
  5. ; Module Version Number:  1.0
  6. ; Module Entry Points:
  7. ;    DBUFFER        DFREE        DIRALPHA    DIRF
  8. ;    DIRFS        DIRLOAD        DIRNPACK    DIRPACK
  9. ;    DIRSEL        DIRSLOAD    DPARAMS        FSIZE
  10. ; Module External References:
  11. ;    PRINT
  12. ;
  13. ;*
  14. ;*  EXTERNALS
  15. ;*
  16.     EXT    PRINT    ; PRINT STRING PTED TO BY RETURN ADDRESS
  17.  
  18. ;*
  19. ;*  BASIC EQUATES
  20. ;*
  21. CPM    EQU    0    ; CP/M WARM BOOT
  22. BIOS    EQU    CPM+1    ; BIOS BASE ADDRESS
  23. BDOS    EQU    CPM+5    ; BDOS ENTRY POINT
  24. ESIZE    EQU    16    ; NUMBER OF BYTES/ENTRY IN MEMORY BUFFER
  25. BUFF    EQU    CPM+80H    ; DEFAULT DMA BUFFER
  26.  
  27. ;**************************************************************************
  28.  
  29. ;*
  30. ;*  GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITHOUT SIZING INFORMATION
  31. ;*    THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES
  32. ;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL.  ON EXIT, 
  33. ;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER.
  34. ;*    THE DIRECTORY BUFFER GENERATED BY DIRF CONTAINS ENTRIES WHICH MAY NOT
  35. ;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE.  THE
  36. ;* DIRFS ROUTINE IS DESIGNED FOR THIS PURPOSE.  THE BASIC TRADEOFF BETWEEN
  37. ;* THE TWO ROUTINES IS THE DIRF RUNS FASTER THAN DIRFS, AND THIS IS NOTICABLE
  38. ;* IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED.
  39. ;*
  40. ;*    INPUT PARAMETERS:
  41. ;*    HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG:
  42. ;*            Bit 7 - Select Non-Sys, Bit 6 - Select Sys
  43. ;*            Bit 5 - Select All Users, Bits 4-0 - User Number
  44. ;*    OUTPUT PARAMETERS:
  45. ;*    HL PTS TO FIRST FILE IN BUFFER
  46. ;*    BC = NUMBER OF FILES
  47. ;*    PSW, DE UNCHANGED
  48. ;*
  49. DIRF::
  50.     PUSH    PSW    ; SAVE PSW
  51.     PUSH    D    ; SAVE PTR TO FCB
  52.  
  53.     ORI    20H    ; SET ALL USERS DUE TO THE WAY DIRLOAD WORKS
  54.     STA    SELFLG    ; SAVE SELECT FLAG FOR DIRSEL
  55.  
  56.     CALL    DBUFFER    ; GET PTRS
  57.  
  58.     CALL    DIRLOAD    ; LOAD DIRECTORY WITHOUT SIZING INFORMATION (FAST LOAD)
  59.  
  60.     POP    D    ; GET PTR TO FCB
  61.     LDA    SELFLG    ; GET SELECT FLAG
  62.     CALL    DIRSEL    ; SELECT FILES
  63.  
  64.     CALL    DIRPACK    ; PACK DIRECTORY
  65.  
  66.     MVI    A,0    ; SORT FLAG
  67.     CALL    DIRALPHA    ; ALPHABETIZE
  68.  
  69.     POP    PSW    ; GET PSW
  70.     RET
  71.  
  72. ;**************************************************************************
  73.  
  74. ;*
  75. ;*  BUFFERS
  76. ;*
  77. TFCB:
  78.     DB    0,'???????????',0,0,0,0    ; TEMPORARY FCB (FN,FT WILD)
  79.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  80.     DB    0,0,0
  81. BLKSHF:
  82.     DS    1    ; BLOCK SHIFT FACTOR
  83. BLKMSK:
  84.     DS    1    ; BLOCK MASK
  85. BLKMAX:
  86.     DS    2    ; MAX NUMBER OF BLOCKS
  87. DIRMAX:
  88.     DS    2    ; MAX NUMBER OF DIRECTORY ENTRIES
  89. SELFLG:
  90.     DS    1    ; FILE ATTRIBUTE FLAG
  91. CMP$FLAG:
  92.     DS    1    ; 0=SORT BY FILE NAME/TYPE, ELSE BY TYPE/NAME
  93. ORDER:
  94.     DS    2    ; POINTER TO ORDER TABLE
  95. DIRBUF:
  96.     DS    2    ; POINTER TO DIRECTORY
  97. DSTART:
  98.     DS    2    ; POINTER TO FIRST DIRECTORY ENTRY
  99. EXTENT:
  100.     DB    0    ; NUMBER OF EXTENT "0" (INITIALIZED TO 0)
  101. FCOUNT:
  102.     DS    2    ; TOTAL NUMBER OF FILES/NUMBER OF SELECTED FILES
  103. HOLD:
  104.     DS    35    ; EXCHANGE HOLD BUFFER FOR FCB'S
  105. PTPTR:
  106.     DS    2    ; POINTER POINTER
  107. PTDIR:
  108.     DS    2    ; DIRECTORY POINTER
  109. I:
  110.     DS    2    ; INDEXES FOR SORT
  111. J:
  112.     DS    2
  113. JG:
  114.     DS    2
  115. N:
  116.     DS    2    ; NUMBER OF ELEMENTS TO SORT
  117. GAP:
  118.     DS    2    ; BINARY GAP SIZE
  119.  
  120. ;**************************************************************************
  121.  
  122. ;*
  123. ;*  GENERAL-PURPOSE DIRECTORY SELECT ROUTINE WITH SIZING INFORMATION
  124. ;*    THIS ROUTINE SCANS FOR THE FCB PTED TO BY DE AND LOADS ALL ENTRIES
  125. ;* WHICH MATCH IT INTO THE MEMORY BUFFER PTED TO BY HL.  ON EXIT, 
  126. ;* BC=NUMBER OF FILES IN BUFFER, AND HL PTS TO FIRST FILE IN BUFFER.
  127. ;*    THE DIRECTORY BUFFER GENERATED BY DIRFS CONTAINS ENTRIES WHICH MAY
  128. ;* BE USED TO COMPUTE THE SIZE OF THE FILES USING THE FSIZE ROUTINE.  THE
  129. ;* DIRFS ROUTINE IS DESIGNED FOR THIS PURPOSE.  THE BASIC TRADEOFF BETWEEN
  130. ;* THE DIRF AND DIRFS ROUTINES IS THE DIRF RUNS FASTER THAN DIRFS, AND THIS
  131. ;* IS NOTICABLE IF THERE IS A SIGNIFICANT NUMBER OF FILES TO BE PROCESSED.
  132. ;*
  133. ;*    INPUT PARAMETERS:
  134. ;*    HL PTS TO BUFFER, DE PTS TO FCB, A IS SELECT FLAG:
  135. ;*            Bit 7 - Select Non-Sys, Bit 6 - Select Sys
  136. ;*            Bit 5 - Select All Users, Bits 4-0 - User Number
  137. ;*    OUTPUT PARAMETERS:
  138. ;*    HL PTS TO FIRST FILE IN BUFFER
  139. ;*    BC = NUMBER OF FILES
  140. ;*    PSW, DE UNCHANGED
  141. ;*
  142. DIRFS::
  143.     PUSH    PSW    ; SAVE PSW
  144.     PUSH    D    ; SAVE PTR TO FCB
  145.  
  146.     STA    SELFLG    ; SAVE SELECT FLAG FOR DIRSEL
  147.  
  148.     CALL    DBUFFER    ; GET PTRS
  149.  
  150.     CALL    DIRSLOAD    ; LOAD DIRECTORY WITH SIZING INFORMATION
  151.  
  152.     POP    D    ; GET PTR TO FCB
  153.     LDA    SELFLG    ; GET SELECT FLAG
  154.     CALL    DIRSEL    ; SELECT FILES
  155.  
  156.     CALL    DIRPACK    ; PACK DIRECTORY
  157.  
  158.     MVI    A,0    ; SORT FLAG
  159.     CALL    DIRALPHA    ; ALPHABETIZE
  160.  
  161.     POP    PSW    ; GET PSW
  162.     RET
  163.  
  164. ;**************************************************************************
  165.  
  166. ;*
  167. ;*  THIS ROUTINE ACCEPTS A BASE ADDRESS FOR THE DYNAMIC BUFFERS
  168. ;*    REQUIRED, DETERMINES HOW MUCH SPACE IS REQUIRED FOR THE BUFFERS,
  169. ;*    AND SETS THE ORDER PTR TO PT TO THE FIRST AND DIRBUF TO PT TO
  170. ;*    THE SECOND (ORDER SPACE = DIRMAX*2 AND DIRBUF = DIRMAX * ESIZE)
  171. ;*  ON INPUT, HL PTS TO AVAILABLE BASE
  172. ;*  ON OUTPUT, HL PTS TO DIRBUF
  173. ;*    A=0 AND ZERO FLAG SET IF BDOS OVERRUN
  174. ;*
  175. DBUFFER::
  176.     PUSH    D    ; SAVE DE
  177.     PUSH    B    ; SAVE BC
  178.     SHLD    ORDER    ; PT TO ORDER TABLE
  179.     CALL    DPARAMS    ; GET PARAMETERS
  180.     LHLD    DIRMAX    ; NUMBER OF ENTRIES IN DIR
  181.     XCHG        ; ... IN DE
  182.     LHLD    ORDER    ; ADD TO ORDER BASE
  183.     DAD    D    ; *1
  184.     CALL    MEMCHK    ; CHECK FOR WITHIN RANGE
  185.     DAD    D    ; HL PTS TO DIRBUF
  186.     CALL    MEMCHK    ; CHECK FOR WITHIN RANGE
  187.     SHLD    DIRBUF    ; SET PTR AND HL PTS TO DIRECTORY BUFFER
  188.     POP    B    ; RESTORE BC
  189.     POP    D    ; RESTORE DE
  190.     MVI    A,0FFH    ; OK
  191.     ORA    A    ; SET FLAGS
  192.     RET
  193.  
  194. MEMCHK:
  195.     PUSH    H    ; SAVE REGS
  196.     PUSH    D
  197.     XCHG        ; NEXT ADDRESS IN DE
  198.     LHLD    BDOS+1    ; GET ADDRESS OF BDOS
  199.     MOV    A,D    ; CHECK FOR PAGE OVERRUN
  200.     CMP    H
  201.     JNC    MEMORUN    ; OVERRUN IF D>=H
  202.     POP    D
  203.     POP    H
  204.     RET
  205. MEMORUN:
  206.     POP    D    ; RESTORE
  207.     POP    H
  208.     XRA    A    ; RETURN 0
  209.     POP    B    ; CLEAR STACK
  210.     POP    B    ; RESTORE BC
  211.     RET
  212.  
  213. ;**************************************************************************
  214.  
  215. ;*
  216. ;*  THIS ROUTINE EXTRACTS DISK PARAMETER INFORMATON FROM THE DPB AND
  217. ;*    STORES THIS INFORMATION IN:
  218. ;*    BLKSHF    <-- BLOCK SHIFT FACTOR (1 BYTE)
  219. ;*    BLKMSK    <-- BLOCK MASK (1 BYTE)
  220. ;*    EXTENT  <-- EXTENT MASK (1 BYTE)
  221. ;*    BLKMAX    <-- MAX NUMBER OF BLOCKS ON DISK (2 BYTES)
  222. ;*    DIRMAX    <-- MAX NUMBER OF DIRECTORY ENTRIES (2 BYTES)
  223. ;*
  224. DPARAMS::
  225.     PUSH    B    ; SAVE REGS
  226.     PUSH    D
  227.     PUSH    H
  228.     PUSH    PSW
  229.     MVI    C,12    ; GET VERSION NUMBER
  230.     CALL    BDOS
  231.     MOV    A,H    ; CHECK FOR 1.4
  232.     ORA    L
  233.     JZ    DPARM1    ; PRE-2.x...GET PARAMS THE 1.4 WAY
  234.  
  235. ;*
  236. ;*  VERSION 2.x OR MP/M
  237. ;*
  238.     MVI    C,31    ; 2.x OR MP/M...REQUEST DPB
  239.     CALL    BDOS
  240.     INX    H
  241.     INX    H
  242.     MOV    A,M    ; GET BLOCK SHIFT
  243.     STA    BLKSHF    ; BLOCK SHIFT FACTOR
  244.     INX    H    ; GET BLOCK MASK
  245.     MOV    A,M
  246.     STA    BLKMSK    ; BLOCK MASK
  247.     INX    H
  248.     MOV    A,M    ; GET MAX EXTENT NUMBER
  249.     STA    EXTENT    ; THIS IS CALLED THE EXTENT MASK
  250.     INX    H
  251.     MOV    E,M    ; GET MAX BLOCK NUMBER
  252.     INX    H
  253.     MOV    D,M
  254.     XCHG
  255.     INX    H    ; ADD 1 FOR MAX NUMBER OF BLOCKS
  256.     SHLD    BLKMAX    ; MAXIMUM NUMBER OF BLOCKS
  257.     XCHG
  258.     INX    H
  259.     MOV    E,M    ; GET DIRECTORY SIZE
  260.     INX    H
  261.     MOV    D,M
  262.     XCHG
  263.     INX    H    ; ADD 1 FOR NUMBER OF ENTRIES
  264.     SHLD    DIRMAX    ; MAXIMUM NUMBER OF DIRECTORY ENTRIES
  265.     JMP    DPARM2
  266.  
  267. ;*
  268. ;*  CP/M 1.4
  269. ;*
  270. DPARM1:
  271.     LHLD    BDOS+1    ; GET PARAMS 1.4 STYLE
  272.     MVI    L,3BH    ; POINT TO DIRECTORY SIZE ENTRY IN 1.4 BDOS
  273.     MOV    E,M    ; GET IT
  274.     MVI    D,0    ; FORCE HI ORDER BYTE TO 0
  275.     XCHG        ; SAVE SIZE OF DIRECTORY ENTRY
  276.     INX    H    ; ADD 1
  277.     SHLD    DIRMAX    ; MAXIMUM NUMBER OF ENTRIES
  278.     XCHG
  279.     INX    H    ; POINT TO BLOCK SHIFT
  280.     MOV    A,M
  281.     STA    BLKSHF    ; BLOCK SHIFT FACTOR
  282.     INX    H    ; POINT TO BLOCK MASK
  283.     MOV    A,M
  284.     STA    BLKMSK    ; BLOCK MASK
  285.     INX    H
  286.     MOV    E,M    ; GET MAXIMUM BLOCK NUMBER
  287.     MVI    D,0
  288.     XCHG
  289.     INX    H    ; ADD 1
  290.     SHLD    BLKMAX    ; MAXIMUM NUMBER OF BLOCKS
  291.     XRA    A    ; A=0
  292.     STA    EXTENT    ; SET EXTENT MASK TO 0 FOR CP/M 1.4 EXTENT SIZE
  293.  
  294. ;*
  295. ;*  ALL PARAMETERS EXTRACTED
  296. ;*
  297. DPARM2:
  298.     POP    PSW    ; RESTORE REGS
  299.     POP    H
  300.     POP    D
  301.     POP    B
  302.     RET
  303.  
  304. ;**************************************************************************
  305.  
  306. ;*
  307. ;*  COMPUTE AMOUNT OF FREE SPACE LEFT ON DISK
  308. ;*    ON EXIT, DE=AMOUNT OF FREE SPACE ON DISK IN K
  309. ;*    THE DPARAMS ROUTINE MUST BE CALLED BEFORE THIS ROUTINE IS USED
  310. ;*
  311. DFREE::
  312.     PUSH    B    ; SAVE REGS
  313.     PUSH    H
  314.     PUSH    PSW
  315.     MVI    C,27    ; GET ADDRESS OF ALLOCATION VECTOR
  316.     CALL    BDOS
  317.     XCHG
  318.     LHLD    BLKMAX    ; GET LENGTH OF ALLOCATION VECTOR
  319.     LXI    B,0    ; INIT BLOCK COUNT TO 0
  320.  
  321. ;*
  322. ;*  BC IS ACCUMULATOR FOR SPACE
  323. ;*
  324. FREE1:
  325.     PUSH    D    ; SAVE ALLOC ADDRESS
  326.     LDAX    D    ; GET BIT PATTERN OF ALLOCATION BYTE
  327.     MVI    E,8    ; SET TO PROCESS 8 BLOCKS
  328. FREE2:
  329.     RAL        ; ROTATE ALLOCATED BLOCK BIT INTO CARRY FLAG
  330.     JC    FREE3    ; IF SET (BIT=1), BLOCK IS ALLOCATED
  331.     INX    B    ; IF NOT SET, BLOCK IS NOT ALLOCATED, SO INCREMENT
  332.             ;   FREE BLOCK COUNT
  333. FREE3:
  334.     MOV    D,A    ; SAVE REMAINING ALLOCATION BITS IN D
  335.     DCX    H    ; COUNT DOWN NUMBER OF BLOCKS ON DISK
  336.     MOV    A,L
  337.     ORA    H
  338.     JZ    FREE4    ; DONE IF NO MORE BLOCKS LEFT
  339.     MOV    A,D    ; A=CURRENT ALLOCATION BIT PATTERN
  340.     DCR    E    ; HAVE ALL 8 BITS BEEN EXAMINED?
  341.     JNZ    FREE2    ; CONTINUE IF NOT
  342.     POP    D    ; GET POINTER TO ALLOCATION VECTOR
  343.     INX    D    ; POINT TO NEXT ALLOCATION BYTE
  344.     JMP    FREE1    ; CONTINUE BY PROCESSING NEXT ALLOCATION BYTE
  345.  
  346. ;*
  347. ;*  BC = TOTAL AMOUNT OF FREE SPACE IN TERMS OF BLOCKS
  348. ;*
  349. FREE4:
  350.     POP    D    ; CLEAR DE FROM STACK
  351.     MOV    L,C    ; HL=BC=NUMBER OF FREE BLOCKS
  352.     MOV    H,B
  353.     LDA    BLKSHF    ; GET BLOCK SHIFT FACTOR
  354.     SUI    3    ; CONVERT NUMBER OF BLOCKS TO K
  355.     JZ    FREE6    ; DONE IF SINGLE DENSITY (1K PER BLOCK)
  356.  
  357. ;*
  358. ;*  WE ARE AT A MORE ADVANCED DENSITY LEVEL; MULTIPLY THE NUMBER OF BLOCKS
  359. ;*    BY THE SIZE OF A BLOCK IN K
  360. ;*
  361. FREE5:
  362.     DAD    H    ; 2, 4, 8, 16, ETC K/BLK, SO BLOCK SHIFT FACTOR
  363.     DCR    A    ;   IS A POWER-OF-TWO MULTIPLE
  364.     JNZ    FREE5
  365.  
  366. ;*
  367. ;*  AT THIS POINT, HL=AMOUNT OF FREE SPACE ON DISK IN K
  368. ;*
  369. FREE6:
  370.     XCHG        ; DE=ANSWER
  371.     POP    PSW    ; RESTORE REGS
  372.     POP    H
  373.     POP    B
  374.     RET
  375.  
  376. ;**************************************************************************
  377.  
  378. ;*
  379. ;*  COMPUTE SIZE OF FILE WHOSE LAST EXTENT IS POINTED TO BY HL
  380. ;*    FILE SIZE IS RETURNED IN DE IN K
  381. ;*  NOTE THAT THE ROUTINE DPARAMS MUST HAVE BEEN CALLED BEFORE THIS ROUTINE
  382. ;*    IS USED
  383. ;*
  384. FSIZE::
  385.     PUSH    B    ; SAVE REGS
  386.     PUSH    H
  387.     PUSH    PSW
  388.     LXI    D,12    ; POINT TO EXTENT
  389.     DAD    D
  390.     MOV    E,M    ; GET EXTENT #
  391.     MVI    D,0
  392.     INX    H    ; SKIP S1
  393.     INX    H    ; SKIP S2
  394.     INX    H    ; HL PTS TO RECORD COUNT FIELD
  395.     MOV    A,M    ; GET RECORD COUNT OF LAST EXTENT
  396.     XCHG
  397.     DAD    H    ; NUMBER OF EXTENTS TIMES 16K
  398.     DAD    H
  399.     DAD    H
  400.     DAD    H
  401.     XCHG        ; TOTAL SIZE OF PREVIOUS EXTENTS IN DE
  402.     LXI    H,BLKMSK
  403.     ADD    M    ; ROUND LAST EXTENT TO BLOCK SIZE
  404.     RRC
  405.     RRC        ; CONVERT FROM RECORDS TO K
  406.     RRC
  407.     ANI    1FH
  408.     MOV    L,A    ; ADD SIZE OF LAST EXTENT TO TOTAL OF PREVIOUS EXTENTS
  409.     MVI    H,0    ; HL=SIZE OF LAST EXTENT, DE=TOTAL OF PREVIOUS EXTENTS
  410.     DAD    D    ; HL=TOTAL FILE SIZE IN BLOCKS
  411.     LDA    BLKMSK    ; GET RECORDS/BLK-1
  412.     RRC
  413.     RRC        ; CONVERT TO K/BLK
  414.     RRC
  415.     ANI    1FH
  416.     CMA        ; USE TO FINISH ROUNDING
  417.     ANA    L
  418.     MOV    L,A    ; HL NOW EQUALS THE SIZE OF THE FILE IN K INCREMENTS
  419.     XCHG        ; DE=FILE SIZE IN K
  420.     POP    PSW    ; RESTORE REGS
  421.     POP    H
  422.     POP    B
  423.     RET
  424.  
  425. ;**************************************************************************
  426.  
  427. ;*
  428. ;*  BUILD DIRECTORY TABLE AT DIRBUF
  429. ;*    THIS IS THE OPTIMAL DIRECTORY LOAD ROUTINE; IT ONLY LOADS UNIQUE
  430. ;*        FILE NAMES FROM DISK, BUT THE INFORMATION IS NOT SUFFICIENT
  431. ;*        TO COMPUTE THE FILE SIZES
  432. ;*    ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX)
  433. ;*    ON OUTPUT, BC IS NUM OF FILES
  434. ;*        DE, HL, PSW UNAFFECTED
  435. ;*
  436. DIRLOAD::
  437.     PUSH    H    ; SAVE REGISTERS
  438.     PUSH    D
  439.     XRA    A    ; JUST SELECT FILES FROM CURRENT DISK
  440.     STA    TFCB    ; SET DR FIELD TO ZERO TO DO THIS
  441.     SHLD    DIRBUF    ; SAVE PTR TO DIRECTORY BUFFER
  442. ;*
  443. ;*  THIS SECTION OF CODE INITIALIZES THE COUNTERS USED
  444. ;*
  445.     LXI    H,0    ; HL=0
  446.     SHLD    FCOUNT    ; TOTAL FILES ON DISK = 0
  447. ;*
  448. ;*  NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER
  449. ;*
  450.     MVI    C,17    ; SEARCH FOR FILE
  451.     LXI    D,TFCB    ; PT TO WILD NAME
  452.     CALL    BDOS
  453.     CPI    255    ; NO MATCH?
  454.     JZ    DIRDN
  455. DIRLP:
  456.     CALL    PENTRY    ; PLACE ENTRY IN DIR
  457.     JZ    DIROVFL    ; MEMORY OVERFLOW ERROR
  458.     MVI    C,18    ; SEARCH FOR NEXT MATCH
  459.     CALL    BDOS
  460.     CPI    255    ; DONE?
  461.     JNZ    DIRLP
  462. ;*
  463. ;*  NOW WE ARE DONE WITH THE LOAD -- SET UP RETURN VALUES
  464. ;*
  465. DIRDN:
  466.     MVI    A,0FFH    ; LOAD OK
  467.     ORA    A    ; SET FLAGS
  468. DIRDNX:
  469.     LHLD    FCOUNT    ; GET TOTAL NUMBER OF FILES
  470.     MOV    B,H    ; ... IN BC
  471.     MOV    C,L
  472. ;*
  473. ;*  RESTORE REGISTERS AND RETURN
  474. ;*
  475.     POP    D
  476.     POP    H
  477.     RET
  478. ;*
  479. ;*  MEMORY OVERFLOW ERROR
  480. ;*
  481. DIROVFL:
  482.     XRA    A    ; LOAD ERROR
  483.     JMP    DIRDNX
  484.  
  485. ;*
  486. ;*  PENTRY --
  487. ;*  PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY
  488. ;*
  489. ;*  ON INPUT,  A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB
  490. ;*          FCOUNT=NUMBER OF FILES IN DIR SO FAR
  491. ;*  ON OUTPUT, FCOUNT=NUMBER OF FILES IN DIR SO FAR
  492. ;*          A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR
  493. ;*
  494. PENTRY:
  495.     PUSH    B    ; SAVE REGS
  496.     PUSH    D
  497.     PUSH    H
  498.     RRC        ; MULTIPLY BY 32 FOR OFFSET COMPUTATION
  499.     RRC
  500.     RRC
  501.     ANI    60H    ; A=BYTE OFFSET
  502.     LXI    D,BUFF    ; PT TO BUFFER ENTRY
  503.     MOV    L,A    ; LET HL=OFFSET
  504.     MVI    H,0
  505.     DAD    D    ; HL=PTR TO FCB
  506.     MOV    A,M    ; GET USER NUMBER
  507.     CPI    0E5H    ; DELETED?
  508.     JZ    PEDONE    ; SKIP IT IF DELETED
  509. ;*
  510. ;*  HL=ADR OF FCB IN BUFF
  511. ;*
  512.  
  513. ;*  INCREMENT TOTAL NUMBER OF FILES
  514.     PUSH    H    ; SAVE PTR TO FCB
  515.     LHLD    FCOUNT    ; TOTAL FILES = TOTAL FILES + 1
  516.     INX    H
  517.     SHLD    FCOUNT
  518.     POP    H    ; GET PTR TO FCB
  519.  
  520. ;*
  521. ;*  COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER
  522. ;*
  523.     XCHG        ; SAVE PTR IN DE
  524.     LHLD    DIRBUF    ; PT TO NEXT ENTRY LOCATION
  525.     XCHG        ; HL PTS TO FCB, DE PTS TO NEXT ENTRY LOCATION
  526.     MVI    B,ESIZE    ; NUMBER OF BYTES/ENTRY
  527.     CALL    MOVE    ; COPY FCB INTO MEMORY BUFFER
  528.     XCHG        ; HL PTS TO NEXT ENTRY
  529.     SHLD    DIRBUF    ; SET PTR
  530.     XCHG        ; PTR TO NEXT ENTRY IN DE
  531.     LHLD    BDOS+1    ; BASE ADDRESS OF BDOS IN HL
  532.     MOV    A,H    ; GET BASE PAGE OF BDOS
  533.     SUI    9    ; COMPUTE 1 PAGE IN FRONT OF BASE PAGE OF CCP
  534.     CMP    D    ; IS PTR TO NEXT ENTRY BEYOND THIS?
  535.     JNZ    PEDONE    ; OK IF NOT AT BUFFER OVERFLOW LEVEL
  536.  
  537. ;*  DONE WITH PENTRY WITH MEMORY OVERFLOW ERROR
  538. PEOVFL:
  539.     XRA    A    ; ERROR
  540.     POP    H    ; RESTORE REGS
  541.     POP    D
  542.     POP    B
  543.     RET
  544.  
  545. ;*  DONE WITH PENTRY AND NO ERROR
  546. PEDONE:
  547.     MVI    A,0FFH    ; NO ERROR
  548.     ORA    A    ; SET FLAGS
  549.     POP    H    ; RESTORE REGS
  550.     POP    D
  551.     POP    B
  552.     RET
  553.  
  554. ;*
  555. ;*  COPY FROM HL TO DE FOR B BYTES
  556. ;*
  557. MOVE:
  558.     MOV    A,M    ; GET BYTE
  559.     STAX    D    ; PUT BYTE
  560.     INX    H    ; PT TO NEXT
  561.     INX    D
  562.     DCR    B    ; COUNT DOWN
  563.     JNZ    MOVE
  564.     RET
  565.  
  566. ;**************************************************************************
  567.  
  568. ;*
  569. ;*  BUILD DIRECTORY TABLE AT DIRBUF
  570. ;*    THIS DIRECTORY LOAD ROUTINE IS MUST LESS EFFICIENT THAN DIRLOAD,
  571. ;*        BUT IT DOES LOAD ENOUGH INFORMATION TO COMPUTE THE FILE
  572. ;*        SIZES USING THE FSIZE ROUTINE
  573. ;*    ON INPUT, HL PTS TO DIRECTORY BUFFER (16 x N MAX)
  574. ;*    ON OUTPUT, BC IS NUM OF FILES
  575. ;*        DE, HL, PSW UNAFFECTED
  576. ;*
  577. DIRSLOAD::
  578.     PUSH    H    ; SAVE REGISTERS
  579.     PUSH    D
  580.     MVI    A,'?'    ; SELECT ALL ENTRIES FROM CURRENT DISK
  581.     STA    TFCB    ; SET DR FIELD TO '?' TO DO THIS
  582.     SHLD    DIRBUF    ; SAVE PTR TO DIRECTORY BUFFER
  583.     SHLD    DSTART    ; SET PTR TO FIRST DIRECTORY ELEMENT
  584. ;*
  585. ;*  THIS SECTION OF CODE INITIALIZES THE COUNTERS USED
  586. ;*
  587.     LXI    H,0    ; HL=0
  588.     SHLD    FCOUNT    ; TOTAL FILES ON DISK = 0
  589. ;*
  590. ;*  NOW WE BEGIN SCANNING FOR FILES TO PLACE INTO THE MEMORY BUFFER
  591. ;*
  592.     MVI    C,17    ; SEARCH FOR FILE
  593.     LXI    D,TFCB    ; PT TO WILD NAME
  594.     CALL    BDOS
  595.     CPI    255    ; NO MATCH?
  596.     JZ    DIRDN
  597. DIRSLP:
  598.     CALL    PSENTRY    ; PLACE ENTRY IN DIR
  599.     JZ    DIROVFL    ; MEMORY OVERFLOW ERROR
  600.     MVI    C,18    ; SEARCH FOR NEXT MATCH
  601.     CALL    BDOS
  602.     CPI    255    ; DONE?
  603.     JNZ    DIRSLP
  604.     JMP    DIRDN    ; DONE
  605.  
  606. ;*
  607. ;*  PSENTRY --
  608. ;*  PLACE ENTRY IN DIRECTORY BUFFER IF NOT AN ERASED ENTRY
  609. ;*    IF ANOTHER ENTRY BY THE SAME NAME IS ALREADY THERE, DETERMINE WHICH
  610. ;*    HAS THE LARGER EXTENT AND PLACE THAT ONE
  611. ;*
  612. ;*  ON INPUT,  A=0-3 FOR ADR INDEX IN BUFF OF ENTRY FCB
  613. ;*          FCOUNT=NUMBER OF FILES IN DIR SO FAR
  614. ;*  ON OUTPUT, FCOUNT=NUMBER OF FILES IN DIR SO FAR
  615. ;*          A=0 AND ZERO FLAG SET IF MEMORY OVERFLOW ERROR
  616. ;*
  617. PSENTRY:
  618.     PUSH    B    ; SAVE REGS
  619.     PUSH    D
  620.     PUSH    H
  621.     RRC        ; MULTIPLY BY 32 FOR OFFSET COMPUTATION
  622.     RRC
  623.     RRC
  624.     ANI    60H    ; A=BYTE OFFSET
  625.     LXI    D,BUFF    ; PT TO BUFFER ENTRY
  626.     MOV    L,A    ; LET HL=OFFSET
  627.     MVI    H,0
  628.     DAD    D    ; HL=PTR TO FCB
  629.     MOV    A,M    ; GET USER NUMBER
  630.     CPI    0E5H    ; DELETED?
  631.     JZ    PEDONE    ; SKIP IT IF DELETED
  632. ;*
  633. ;*  HL=ADR OF FCB IN BUFF
  634. ;*
  635.  
  636. ;*
  637. ;*  SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME
  638. ;*    NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX
  639. ;*    AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT
  640. ;*    FOUND, RETURN WITH ZERO FLAG RESET (NZ)
  641. ;*
  642.     CALL    DUPENTRY    ; SCAN FOR DUPLICATE ENTRIES (BY NAME ONLY)
  643.     JZ    PEDONE    ; SKIP IF DUPLICATE
  644.  
  645. ;*  INCREMENT TOTAL NUMBER OF FILES
  646.     PUSH    H    ; SAVE PTR TO FCB
  647.     LHLD    FCOUNT    ; TOTAL FILES = TOTAL FILES + 1
  648.     INX    H
  649.     SHLD    FCOUNT
  650.     POP    H    ; GET PTR TO FCB
  651.  
  652. ;*
  653. ;*  COPY FCB PTED TO BY HL INTO DIRECTORY BUFFER
  654. ;*
  655.     XCHG        ; SAVE PTR IN DE
  656.     LHLD    DIRBUF    ; PT TO NEXT ENTRY LOCATION
  657.     XCHG        ; HL PTS TO FCB, DE PTS TO NEXT ENTRY LOCATION
  658.     MVI    B,ESIZE    ; NUMBER OF BYTES/ENTRY
  659.     CALL    MOVE    ; COPY FCB INTO MEMORY BUFFER
  660.     XCHG        ; HL PTS TO NEXT ENTRY
  661.     SHLD    DIRBUF    ; SET PTR
  662.     XCHG        ; PTR TO NEXT ENTRY IN DE
  663.     LHLD    BDOS+1    ; BASE ADDRESS OF BDOS IN HL
  664.     MOV    A,H    ; GET BASE PAGE OF BDOS
  665.     SUI    9    ; COMPUTE 1 PAGE IN FRONT OF BASE PAGE OF CCP
  666.     CMP    D    ; IS PTR TO NEXT ENTRY BEYOND THIS?
  667.     JNZ    PEDONE    ; OK IF NOT AT BUFFER OVERFLOW LEVEL
  668.  
  669. ;*  DONE WITH PENTRY WITH MEMORY OVERFLOW ERROR
  670.     JMP    PEOVFL
  671.  
  672. ;*
  673. ;*  SCAN DIRECTORY ENTRIES AS LOADED SO FAR FOR ANOTHER ENTRY BY THE SAME
  674. ;*    NAME; IF FOUND, SET THAT ENTRY TO BE THE ENTRY WITH THE LARGER EX
  675. ;*    AND RETURN WITH THE ZERO FLAG SET, INDICATING NO NEW FILE; IF NOT
  676. ;*    FOUND, RETURN WITH ZERO FLAG RESET (NZ)
  677. ;*  ON INPUT, HL PTS TO ENTRY TO SCAN FOR, FCOUNT = NUMBER OF ENTRIES SO FAR,
  678. ;*        AND (DSTART) = STARTING ADDRESS OF DIRECTORY LOADED
  679. ;*  ON OUTPUT, A=0 AND ZERO FLAG SET IF DUPLICATE ENTRY FOUND; A=0FFH AND NZ
  680. ;*        IF NO DUP ENTRY FOUND
  681. ;*        ONLY HL NOT AFFECTED
  682. ;*
  683. DUPENTRY:
  684.     PUSH    H    ; SAVE PTR TO ENTRY TO SCAN FOR
  685.     XCHG        ; PTR IN DE
  686.     LHLD    FCOUNT    ; CHECK COUNT
  687.     MOV    A,H    ; NO ENTRIES?
  688.     ORA    L
  689.     JZ    NODUP    ; NO DUPLICATE ENTRY RETURN
  690.     MOV    B,H    ; BC=NUMBER OF ENTRIES
  691.     MOV    C,L
  692.     LHLD    DSTART    ; HL PTS TO FIRST ENTRY
  693. DUPELOOP:
  694.     PUSH    B    ; SAVE COUNT
  695.     PUSH    H    ; SAVE PTRS
  696.     PUSH    D
  697.     MVI    B,12    ; COMPARE USER NUMBER, FN, AND FT
  698.     CALL    COMP
  699.     POP    D    ; RESTORE PTRS
  700.     POP    H
  701.     JNZ    NODUPL    ; CONTINUE LOOKING FOR ANOTHER ENTRY
  702. ;  DUPLICATE ENTRIES HAVE BEEN IDENTIFIED AT THIS POINT
  703.     PUSH    H    ; SAVE PTRS AGAIN
  704.     PUSH    D
  705.     LXI    B,12    ; PT TO EX FIELD
  706.     DAD    B
  707.     XCHG
  708.     DAD    B    ; DE PTS TO DIRECTORY ENTRY, HL PTS TO TARGET
  709.     LDAX    D    ; GET EXTENT FIELD FROM DIRECTORY ENTRY
  710.     CMP    M    ; COMPARE WITH THAT IN TARGET
  711.     POP    D    ; GET PTRS
  712.     POP    H
  713.     JNC    DUPFND
  714. ;  NEW TARGET IS LARGER THAN STORED ENTRY
  715.     XCHG        ; MAKE HL PT TO NEW TARGET, DE PT TO DEST
  716.     MVI    B,ESIZE    ; NUMBER OF BYTES TO MOVE
  717.     CALL    MOVE    ; MOVE IT
  718. ;  RETURN INDICATOR THAT DUPLICATE WAS FOUND
  719. DUPFND:
  720.     POP    B    ; CLEAR COUNT FROM STACK
  721.     XRA    A    ; INDICATE DUP FOUND
  722.     POP    H    ; RESTORE PTR TO ENTRY TO SCAN FOR
  723.     RET
  724. ;  NO DUPLICATE FOUND; ADVANCE TO NEXT ENTRY
  725. NODUPL:
  726.     LXI    B,ESIZE    ; HL PTS TO CURRENT ENTRY IN BUFFER, SO ADD ESIZE TO IT
  727.     DAD    B
  728.     POP    B    ; GET COUNT
  729.     DCX    B    ; COUNT DOWN
  730.     MOV    A,B    ; CHECK FOR DONE
  731.     ORA    C
  732.     JNZ    DUPELOOP
  733. ;  NO DUPLICATE FOUND, PERIOD
  734. NODUP:
  735.     MVI    A,0FFH    ; INDICATE DUP NOT FOUND
  736.     ORA    A    ; SET FLAGS
  737.     POP    H    ; RESTORE PTR TO ENTRY TO SCAN FOR
  738.     RET
  739.  
  740. ;**************************************************************************
  741.  
  742. ;*
  743. ;*  DIRALPHA -- ALPHABETIZES DIRECTORY PTED TO BY HL; BC CONTAINS
  744. ;*    THE NUMBER OF FILES IN THE DIRECTORY AND A = SORT FLAG
  745. ;*    (0=SORT BY FILE NAME/TYPE, <>0 = SORT BY FILE TYPE/NAME)
  746. ;*
  747. DIRALPHA::
  748.     STA    CMP$FLAG    ; SET FLAG
  749.     MOV    A,B    ; ANY FILES?
  750.     ORA    C
  751.     RZ
  752.     PUSH    H    ; SAVE REGS
  753.     PUSH    D
  754.     PUSH    B
  755.     SHLD    DIRBUF    ; SAVE PTR TO DIRECTORY
  756.     PUSH    H    ; SAVE HL
  757.     MOV    H,B    ; HL=BC=FILE COUNT
  758.     MOV    L,C
  759.     SHLD    N    ; SET "N"
  760.     POP    H
  761. ;*
  762. ;*  SHELL SORT --
  763. ;*    THIS SORT ROUTINE IS ADAPTED FROM "SOFTWARE TOOLS"
  764. ;*    BY KERNIGAN AND PLAUGHER, PAGE 106.  COPYRIGHT, 1976, ADDISON-WESLEY.
  765. ;*  ON ENTRY, BC=NUMBER OF ENTRIES
  766. ;*
  767. SORT:
  768.     XCHG        ; POINTER TO DIRECTORY IN DE
  769.     LHLD    ORDER    ; PT TO ORDER TABLE
  770. ;*
  771. ;*  SET UP ORDER TABLE; HL PTS TO NEXT ENTRY IN ORDER TABLE, DE PTS TO NEXT
  772. ;*    ENTRY IN DIRECTORY, BC = NUMBER OF ELEMENTS REMAINING
  773. ;*
  774. SORT1:
  775.     MOV    M,E    ; STORE LOW-ORDER ADDRESS
  776.     INX    H    ; PT TO NEXT ORDER BYTE
  777.     MOV    M,D    ; STORE HIGH-ORDER ADDRESS
  778.     INX    H    ; PT TO NEXT ORDER ENTRY
  779.     PUSH    H    ; SAVE PTR
  780.     LXI    H,ESIZE    ; HL=NUMBER OF BYTES/ENTRY
  781.     DAD    D    ; PT TO NEXT DIR1 ENTRY
  782.     XCHG        ; DE PTS TO NEXT ENTRY
  783.     POP    H    ; GET PTR TO ORDER TABLE
  784.     DCX    B    ; COUNT DOWN
  785.     MOV    A,B    ; DONE?
  786.     ORA    C
  787.     JNZ    SORT1
  788. ;*
  789. ;*  THIS IS THE MAIN SORT LOOP FOR THE SHELL SORT IN "SOFTWARE TOOLS" BY K&P
  790. ;*
  791.  
  792. ;*
  793. ;*  SHELL SORT FROM "SOFTWARE TOOLS" BY KERNINGHAN AND PLAUGER
  794. ;*
  795.     LHLD    N    ; NUMBER OF ITEMS TO SORT
  796.     SHLD    GAP    ; SET INITIAL GAP TO N FOR FIRST DIVISION BY 2
  797.  
  798. ;*  FOR (GAP = N/2; GAP > 0; GAP = GAP/2)
  799. SRTL0:
  800.     ORA    A    ; CLEAR CARRY
  801.     LHLD    GAP    ; GET PREVIOUS GAP
  802.     MOV    A,H    ; ROTATE RIGHT TO DIVIDE BY 2
  803.     RAR
  804.     MOV    H,A
  805.     MOV    A,L
  806.     RAR
  807.     MOV    L,A
  808.  
  809. ;*  TEST FOR ZERO
  810.     ORA    H
  811.     JZ    SDONE    ; DONE WITH SORT IF GAP = 0
  812.  
  813.     SHLD    GAP    ; SET VALUE OF GAP
  814.     SHLD    I    ; SET I=GAP FOR FOLLOWING LOOP
  815.  
  816. ;*  FOR (I = GAP + 1; I <= N; I = I + 1)
  817. SRTL1:
  818.     LHLD    I    ; ADD 1 TO I
  819.     INX    H
  820.     SHLD    I
  821.  
  822. ;*  TEST FOR I <= N
  823.     XCHG        ; I IS IN DE
  824.     LHLD    N    ; GET N
  825.     MOV    A,L    ; COMPARE BY SUBTRACTION
  826.     SUB    E
  827.     MOV    A,H
  828.     SBB    D    ; CARRY SET MEANS I > N
  829.     JC    SRTL0    ; DON'T DO FOR LOOP IF I > N
  830.  
  831.     LHLD    I    ; SET J = I INITIALLY FOR FIRST SUBTRACTION OF GAP
  832.     SHLD    J
  833.  
  834. ;*  FOR (J = I - GAP; J > 0; J = J - GAP)
  835. SRTL2:
  836.     LHLD    GAP    ; GET GAP
  837.     XCHG        ; ... IN DE
  838.     LHLD    J    ; GET J
  839.     MOV    A,L    ; COMPUTE J - GAP
  840.     SUB    E
  841.     MOV    L,A
  842.     MOV    A,H
  843.     SBB    D
  844.     MOV    H,A
  845.     SHLD    J    ; J = J - GAP
  846.     JC    SRTL1    ; IF CARRY FROM SUBTRACTIONS, J < 0 AND ABORT
  847.     MOV    A,H    ; J=0?
  848.     ORA    L
  849.     JZ    SRTL1    ; IF ZERO, J=0 AND ABORT
  850.  
  851. ;*  SET JG = J + GAP
  852.     XCHG        ; J IN DE
  853.     LHLD    GAP    ; GET GAP
  854.     DAD    D    ; J + GAP
  855.     SHLD    JG    ; JG = J + GAP
  856.  
  857. ;*  IF (V(J) <= V(JG))
  858.     CALL    ICOMPARE    ; J IN DE, JG IN HL
  859.  
  860. ;*  ... THEN BREAK
  861.     JC    SRTL1
  862.  
  863. ;*  ... ELSE EXCHANGE
  864.     LHLD    J    ; SWAP J, JG
  865.     XCHG
  866.     LHLD    JG
  867.     CALL    ISWAP    ; J IN DE, JG IN HL
  868.  
  869. ;*  END OF INNER-MOST FOR LOOP
  870.     JMP    SRTL2
  871.  
  872. ;*
  873. ;*  SORT IS DONE -- RESTRUCTURE DIR1 IN SORTED ORDER IN PLACE
  874. ;*
  875. SDONE:
  876.     LHLD    N    ; NUMBER OF ENTRIES
  877.     MOV    B,H    ; ... IN BC
  878.     MOV    C,L
  879.     LHLD    ORDER    ; PTR TO ORDERED POINTER TABLE
  880.     SHLD    PTPTR    ; SET PTR PTR
  881.     LHLD    DIRBUF    ; PTR TO UNORDERED DIRECTORY
  882.     SHLD    PTDIR    ; SET PTR DIR BUFFER
  883.  
  884. ;*  FIND PTR TO NEXT DIR1 ENTRY
  885. SRTDN:
  886.     LHLD    PTPTR    ; PT TO REMAINING POINTERS
  887.     XCHG        ; ... IN DE
  888.     LHLD    PTDIR    ; HL PTS TO NEXT DIR ENTRY
  889.     PUSH    B    ; SAVE COUNT OF REMAINING ENTRIES
  890.  
  891. ;*  FIND PTR TABLE ENTRY
  892. SRTDN1:
  893.     LDAX    D    ; GET CURRENT POINTER TABLE ENTRY VALUE
  894.     INX    D    ; PT TO HIGH-ORDER POINTER BYTE
  895.     CMP    L    ; COMPARE AGAINST DIR1 ADDRESS LOW
  896.     JNZ    SRTDN2    ; NOT FOUND YET
  897.     LDAX    D    ; LOW-ORDER BYTES MATCH -- GET HIGH-ORDER POINTER BYTE
  898.     CMP    H    ; COMPARE AGAINST DIR1 ADDRESS HIGH
  899.     JZ    SRTDN3    ; MATCH FOUND
  900. SRTDN2:
  901.     INX    D    ; PT TO NEXT PTR TABLE ENTRY
  902.     DCX    B    ; COUNT DOWN
  903.     MOV    A,C    ; END OF TABLE?
  904.     ORA    B
  905.     JNZ    SRTDN1    ; CONTINUE IF NOT
  906.  
  907. ;*  FATAL ERROR -- INTERNAL ERROR; POINTER TABLE NOT CONSISTENT
  908. FERR$PTR:
  909.     CALL    PRINT
  910.     DB    0DH,0AH,'DIRALPHA -- Pointer Error',0
  911.     JMP    CPM
  912.  
  913. ;*  FOUND THE POINTER TABLE ENTRY WHICH POINTS TO THE NEXT UNORDERED DIR1 ENTRY
  914. ;*    MAKE BOTH POINTERS (PTR TO NEXT, PTR TO CURRENT UNORDERED DIR1 ENTRY)
  915. ;*    POINT TO SAME LOCATION (PTR TO NEXT DIR1 ENTRY TO BE ORDERED)
  916. SRTDN3:
  917.     LHLD    PTPTR    ; GET PTR TO NEXT ORDERED ENTRY
  918.     DCX    D    ; DE PTS TO LOW-ORDER POINTER ADDRESS
  919.     MOV    A,M    ; MAKE PTR TO NEXT UNORDERED DIR1 PT TO BUFFER FOR
  920.     STAX    D    ;   DIR1 ENTRY TO BE MOVED TO NEXT UNORDERED DIR1 POS
  921.     INX    H    ; PT TO NEXT PTR ADDRESS
  922.     INX    D
  923.     MOV    A,M    ; MAKE HIGH POINT SIMILARLY
  924.     STAX    D
  925.  
  926. ;*  COPY NEXT UNORDERED DIR1 ENTRY TO HOLD BUFFER
  927.     MVI    B,ESIZE    ; B=NUMBER OF BYTES/ENTRY
  928.     LHLD    PTDIR    ; PT TO ENTRY
  929.     LXI    D,HOLD    ; PT TO HOLD BUFFER
  930.     PUSH    B    ; SAVE B=NUMBER OF BYTES/ENTRY
  931.     CALL    MOVE
  932.     POP    B
  933.  
  934. ;*  COPY TO-BE-ORDERED DIR1 ENTRY TO NEXT ORDERED DIR1 POSITION
  935.     LHLD    PTPTR    ; POINT TO ITS POINTER
  936.     MOV    E,M    ; GET LOW-ADDRESS POINTER
  937.     INX    H
  938.     MOV    D,M    ; GET HIGH-ADDRESS POINTER
  939.     LHLD    PTDIR    ; DESTINATION ADDRESS FOR NEXT ORDERED DIR1 ENTRY
  940.     XCHG        ; HL PTS TO ENTRY TO BE MOVED, DE PTS TO DEST
  941.     PUSH    B    ; SAVE B=NUMBER OF BYTES/ENTRY
  942.     CALL    MOVE
  943.     POP    B
  944.     XCHG        ; HL PTS TO NEXT UNORDERED DIR1 ENTRY
  945.     SHLD    PTDIR    ; SET POINTER FOR NEXT LOOP
  946.  
  947. ;*  COPY ENTRY IN HOLD BUFFER TO LOC PREVIOUSLY HELD BY LATEST ORDERED ENTRY
  948.     LHLD    PTPTR    ; GET PTR TO PTR TO THE DESTINATION
  949.     MOV    E,M    ; GET LOW-ADDRESS POINTER
  950.     INX    H
  951.     MOV    D,M    ; HIGH-ADDRESS POINTER
  952.     LXI    H,HOLD    ; HL PTS TO HOLD BUFFER, DE PTS TO ENTRY DEST
  953.     CALL    MOVE    ; B=NUMBER OF BYTES/ENTRY
  954.  
  955. ;*  POINT TO NEXT ENTRY IN POINTER TABLE
  956.     LHLD    PTPTR    ; POINTER TO CURRENT ENTRY
  957.     INX    H    ; SKIP OVER IT
  958.     INX    H
  959.     SHLD    PTPTR
  960.  
  961. ;*  COUNT DOWN
  962.     POP    B    ; GET COUNTER
  963.     DCX    B    ; COUNT DOWN
  964.     MOV    A,C    ; DONE?
  965.     ORA    B
  966.     JNZ    SRTDN
  967.     POP    B    ; RESTORE REGS
  968.     POP    D
  969.     POP    H
  970.     RET        ; DONE
  971.  
  972. ;*
  973. ;*  SWAP (Exchange) the pointers in the ORDER table whose indexes are in
  974. ;*    HL and DE
  975. ;*
  976. ISWAP:
  977.     PUSH    H        ; SAVE HL
  978.     LHLD    ORDER        ; ADDRESS OF ORDER TABLE - 2
  979.     MOV    B,H        ; ... IN BC
  980.     MOV    C,L
  981.     POP    H
  982.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  983.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  984.                 ;   OF ORIGINAL HL (1, 2, ...)
  985.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  986.     XCHG            ; DE NOW PTS TO POINTER INDEXED BY HL
  987.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  988.     DAD    H        ; HL PTS TO OFFSET ADDRESS INDICATED BY INDEX
  989.                 ;   OF ORIGINAL DE (1, 2, ...)
  990.     DAD    B        ; HL NOW PTS TO POINTER INVOLVED
  991.     MOV    C,M        ; EXCHANGE POINTERS -- GET OLD (DE)
  992.     LDAX    D        ; -- GET OLD (HL)
  993.     XCHG            ; SWITCH
  994.     MOV    M,C        ; PUT NEW (HL)
  995.     STAX    D        ; PUT NEW (DE)
  996.     INX    H        ; PT TO NEXT BYTE OF POINTER
  997.     INX    D
  998.     MOV    C,M        ; GET OLD (HL)
  999.     LDAX    D        ; GET OLD (DE)
  1000.     XCHG            ; SWITCH
  1001.     MOV    M,C        ; PUT NEW (DE)
  1002.     STAX    D        ; PUT NEW (HL)
  1003.     RET
  1004. ;*
  1005. ;*  ICOMPARE compares the entry pointed to by the pointer pointed to by HL
  1006. ;*    with that pointed to by DE (1st level indirect addressing); on entry,
  1007. ;*    HL and DE contain the numbers of the elements to compare (1, 2, ...);
  1008. ;*    on exit, Carry Set means ((DE)) < ((HL)), Zero Set means ((HL)) = ((DE)),
  1009. ;*    and Non-Zero and No-Carry means ((DE)) > ((HL))
  1010. ;*
  1011. ICOMPARE:
  1012.     PUSH    H        ; SAVE HL
  1013.     LHLD    ORDER        ; ADDRESS OF ORDER - 2
  1014.     MOV    B,H        ; ... IN BC
  1015.     MOV    C,L
  1016.     POP    H
  1017.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  1018.     DAD    H        ; DOUBLE THE ELEMENT NUMBER TO POINT TO THE PTR
  1019.     DAD    B        ; ADD TO THIS THE BASE ADDRESS OF THE PTR TABLE
  1020.     XCHG            ; RESULT IN DE
  1021.     DCX    H        ; ADJUST INDEX TO 0...N-1 FROM 1...N
  1022.     DAD    H        ; DO THE SAME WITH THE ORIGINAL DE
  1023.     DAD    B
  1024.     XCHG
  1025.  
  1026. ;*
  1027. ;*  HL NOW POINTS TO THE POINTER WHOSE INDEX WAS IN HL TO BEGIN WITH
  1028. ;*  DE NOW POINTS TO THE POINTER WHOSE INDEX WAS IN DE TO BEGIN WITH
  1029. ;*    FOR EXAMPLE, IF DE=5 AND HL=4, DE NOW POINTS TO THE 5TH PTR AND HL
  1030. ;* TO THE 4TH POINTER
  1031. ;*
  1032.     MOV    C,M        ; BC IS MADE TO POINT TO THE OBJECT INDEXED TO
  1033.     INX    H        ; ... BY THE ORIGINAL HL
  1034.     MOV    B,M
  1035.     XCHG
  1036.     MOV    E,M        ; DE IS MADE TO POINT TO THE OBJECT INDEXED TO
  1037.     INX    H        ; ... BY THE ORIGINAL DE
  1038.     MOV    D,M
  1039.     MOV    H,B        ; SET HL = OBJECT PTED TO INDIRECTLY BY BC
  1040.     MOV    L,C
  1041.  
  1042. ;*
  1043. ;*  COMPARE DIR ENTRY PTED TO BY HL WITH THAT PTED TO BY DE;
  1044. ;*    NO NET EFFECT ON HL, DE; RET W/CARRY SET MEANS DE<HL
  1045. ;*    RET W/ZERO SET MEANS DE=HL
  1046. ;*
  1047. CMP$ENTRY:
  1048.     LDA    CMP$FLAG    ; GROUP BY FILE TYPE?
  1049.     ORA    A
  1050.     JZ    CMP$FN$FT
  1051. ;*
  1052. ;*  COMPARE BY FILE TYPE, FILE NAME, EXTENSION, AND USER (IN THAT ORDER)
  1053. ;*
  1054. CMP$FCB1:    
  1055.     PUSH    H
  1056.     PUSH    D
  1057.     LXI    B,9    ; PT TO FT (8 BYTES + 1 BYTE FOR USER NUMBER)
  1058.     DAD    B
  1059.     XCHG
  1060.     DAD    B
  1061.     XCHG        ; DE, HL NOW PT TO THEIR FT'S
  1062.     MVI    B,3    ; 3 BYTES
  1063.     CALL    COMP    ; COMPARE FT'S
  1064.     POP    D
  1065.     POP    H
  1066.     RNZ        ; CONTINUE IF COMPLETE MATCH
  1067.     PUSH    H
  1068.     PUSH    D
  1069.     INX    H    ; PT TO FILE NAME
  1070.     INX    D
  1071.     MVI    B,8    ; 8 BYTES
  1072.     CALL    COMP    ; COMPARE FN'S
  1073.     POP    D
  1074.     POP    H
  1075.     RNZ        ; CONTINUE IF COMPLETE MATCH
  1076.     PUSH    H
  1077.     PUSH    D
  1078.     LXI    B,12    ; PT TO EXT (11 BYTES FOR FN/FT AND 1 BYTE FOR USER)
  1079.     DAD    B
  1080.     XCHG
  1081.     DAD    B
  1082.     XCHG        ; DE, HL NOW PT TO THEIR EXT'S
  1083.     LDAX    D    ; COMPARE
  1084.     CMP    M
  1085.     POP    D
  1086.     POP    H
  1087.     RNZ
  1088.     LDAX    D    ; COMPARE USER NUMBERS
  1089.     CMP    M
  1090.     RET
  1091. ;*
  1092. ;*  COMPARE BY FILE NAME, FILE TYPE, EXTENSION, AND USER NUM (IN THAT ORDER)
  1093. ;*
  1094. CMP$FN$FT:
  1095.     PUSH    H
  1096.     PUSH    D
  1097.     INX    H    ; PT TO FN
  1098.     INX    D
  1099.     MVI    B,12    ; COMPARE FN, FT, EX
  1100.     CALL    COMP
  1101.     POP    D
  1102.     POP    H
  1103.     RNZ
  1104.     LDAX    D    ; COMPARE USER NUMBER
  1105.     CMP    M
  1106.     RET
  1107. ;*
  1108. ;*  COMP COMPARES DE W/HL FOR B BYTES; RET W/CARRY IF DE<HL
  1109. ;*    MSB IS DISREGARDED
  1110. ;*
  1111. COMP:
  1112.     MOV    A,M    ; GET (HL)
  1113.     ANI    7FH    ; MASK MSB
  1114.     MOV    C,A    ; ... IN C
  1115.     LDAX    D    ; COMPARE
  1116.     ANI    7FH    ; MASK MSB
  1117.     CMP    C
  1118.     RNZ
  1119.     INX    H    ; PT TO NEXT
  1120.     INX    D
  1121.     DCR    B    ; COUNT DOWN
  1122.     JNZ    COMP
  1123.     RET
  1124. ;*
  1125. ;*  AS COMP, BUT MATCH ON '?' PTED TO BY HL
  1126. ;*
  1127. COMP2:
  1128.     MOV    A,M    ; GET (HL)
  1129.     ANI    7FH    ; MASK MSB
  1130.     CPI    '?'    ; MATCH '?'
  1131.     JZ    COMP2A
  1132.     MOV    C,A    ; ... IN C
  1133.     LDAX    D    ; COMPARE
  1134.     ANI    7FH    ; MASK MSB
  1135.     CMP    C
  1136.     RNZ
  1137. COMP2A:
  1138.     INX    H    ; PT TO NEXT
  1139.     INX    D
  1140.     DCR    B    ; COUNT DOWN
  1141.     JNZ    COMP2
  1142.     RET
  1143.  
  1144. ;*
  1145. ;*  DIRSEL -- SELECT DIRECTORY ENTRIES WHICH MATCH USER NUMBER, FILE
  1146. ;*    NAME, AND FILE TYPE PTED TO BY DE
  1147. ;*
  1148. ;*  ON INPUT, HL PTS TO DIRECTORY, DE PTS TO FCB, BC=NUMBER OF FILES, A=FLAG:
  1149. ;*            Bit 7 - Select Non-Sys, Bit 6 - Select Sys
  1150. ;*            Bit 5 - Select All Users, Bits 4-0 - User Number
  1151. ;*  ON OUTPUT, THE MS BIT OF THE USER OF THE SELECTED FILES IS SET
  1152. ;*
  1153. DIRSEL::
  1154.     PUSH    H    ; SAVE REGS
  1155.     PUSH    D
  1156.     PUSH    B
  1157.     PUSH    PSW
  1158.     STA    SELFLG    ; SAVE SELECT FLAG
  1159.     SHLD    DIRBUF    ; SAVE PTR
  1160.     PUSH    B    ; SAVE COUNT
  1161.  
  1162. ;*  CHECK FOR MATCH
  1163. DSMAT:
  1164.     POP    B    ; GET COUNT
  1165.     MOV    A,B    ; CHECK FOR NO ENTRIES
  1166.     ORA    C
  1167.     JZ    DSDONE    ; DONE IF NONE
  1168.     DCX    B    ; COUNT DOWN
  1169.     PUSH    B    ; SAVE COUNT
  1170.     PUSH    H    ; SAVE PTRS
  1171.     PUSH    D
  1172.     INX    H    ; PT TO FN
  1173.     INX    D
  1174.     MVI    B,8    ; CHECK 8 CHARS
  1175.     XCHG        ; LET HL PT TO FCB
  1176.     CALL    COMP2    ; COMPARE WITH '?' MATCH
  1177.     POP    D    ; GET PTRS
  1178.     POP    H
  1179.     JNZ    DSMATNX    ; ADVANCE TO NEXT ENTRY IF NO MATCH
  1180.     PUSH    H    ; SAVE PTRS
  1181.     PUSH    D
  1182.     LXI    B,9    ; CHECK R/O FLAG, SYS FLAG, LAST BYTE
  1183.     DAD    B
  1184.     XCHG
  1185.     DAD    B    ; DON'T EXCHANGE -- HL PTS TO FCB, DE PTS TO DIR
  1186.     MVI    B,3    ; CHECK 3 BYTES
  1187.     CALL    COMP2    ; COMPARE WITH '?' MATCH
  1188.     POP    D    ; RESTORE PTRS
  1189.     POP    H
  1190.     JNZ    DSMATNX    ; NO MATCH?
  1191.     CALL    FLGCHK    ; CHECK FLAGS
  1192.     JNZ    DSMATNX    ; NO MATCH?
  1193.  
  1194. ;*
  1195. ;*  WE HAVE A MATCH -- MARK ENTRY
  1196. ;*
  1197. DSMARK:
  1198.     MOV    A,M    ; GET BYTE
  1199.     ORI    80H    ; SET MSB
  1200.     MOV    M,A    ; PUT BYTE
  1201.  
  1202. ;*
  1203. ;*  ADVANCE TO NEXT ENTRY
  1204. ;*
  1205. DSMATNX:
  1206.     LXI    B,ESIZE    ; NUMBER OF BYTES/ENTRY
  1207.     DAD    B    ; PT TO NEXT ENTRY
  1208.     JMP    DSMAT    ; CONTINUE
  1209.  
  1210. ;*
  1211. ;*  DONE WITH SCAN
  1212. ;*
  1213. DSDONE:
  1214.     POP    PSW        ; RESTORE REGS
  1215.     POP    B
  1216.     POP    D
  1217.     POP    H
  1218.     RET
  1219.  
  1220. ;*
  1221. ;*  WE HAVE A NAME MATCH -- NOW CHECK FLAGS
  1222. ;*    RETURN Z IF MATCH, NZ IF NO MATCH
  1223. ;*
  1224. FLGCHK:
  1225.     PUSH    D    ; SAVE FCB PTR
  1226.     PUSH    H    ; SAVE ENTRY PTR
  1227.     LXI    D,10    ; CHECK SYSTEM BIT
  1228.     DAD    D    ; HL PTS TO SYSTEM BIT
  1229.     MOV    A,M    ; GET BYTE
  1230.     POP    H    ; RESTORE PTRS
  1231.     POP    D
  1232.     ANI    80H    ; MASK FOR SYSTEM BIT
  1233.     LDA    SELFLG    ; GET FLAG BYTE
  1234.     JZ    DSNSBIT
  1235. ; IT IS A SYSTEM FILE, SO LOOK AT BIT 6 OF FLAG
  1236.     ANI    40H    ; LOOK AT BIT 6
  1237.     JNZ    DSUSER    ; OK, SO LOOK AT USER
  1238.     JMP    DSNOMAT    ; CONTINUE PROCESSING
  1239. ; IT IS A NON-SYSTEM FILE, SO LOOK AT BIT 7 OF FLAG
  1240. DSNSBIT:
  1241.     ANI    80H    ; LOOK AT BIT 7
  1242.     JZ    DSNOMAT    ; NOT SET, SO SKIP ENTRY AS FAILING TEST
  1243. ; NOW CHECK FOR PROPER USER AREA
  1244. DSUSER:
  1245.     LDA    SELFLG    ; GET FLAG
  1246.     ANI    20H    ; CHECK FOR ALL USERS
  1247.     JNZ    DSYESMAT    ; MATCH IF SET
  1248.     LDA    SELFLG    ; GET FLAG
  1249.     ANI    1FH    ; GET USER NUMBER (LOW 5 BITS)
  1250.     MOV    B,A    ; SAVE IN B
  1251.     MOV    A,M    ; COMPARE USER NUMBER TO DIR ENTRY
  1252.     ANI    1FH    ; LOOK AT USER NUMBER
  1253.     CMP    B    ; COMPARE TO PASSED USER NUMBER
  1254.     JNZ    DSNOMAT    ; SKIP IF NOT SAME USER NUMBER
  1255. ;  MATCH, SO RETURN Z
  1256. DSYESMAT:
  1257.     XRA    A    ; SET ZERO
  1258.     RET
  1259. ;  NOT A MATCH, SO RETURN NZ
  1260. DSNOMAT:
  1261.     MVI    A,0FFH    ; SET NO ZERO
  1262.     ORA    A
  1263.     RET
  1264.  
  1265. ;**************************************************************************
  1266.  
  1267. ;*
  1268. ;*  NEGATIVE DIRECTORY PACK UTILITY -- RESTRUCTURE THE DIRECTORY TO INCLUDE
  1269. ;*    ONLY THOSE ENTRIES NOT MARKED BY DIRSEL
  1270. ;*
  1271. ;*  ON INPUT, HL PTS TO DIRECTORY BUFFER AND BC=NUMBER OF FILES
  1272. ;*  ON EXIT, BC=NUMBER OF SELECTED FILES
  1273. ;*  REQUIRED SIDE EFFECT IS THAT FLAG EXTENT (SET BY DIR::) BE CORRECT
  1274. ;*    (IN MOST CASES, DEFAULT OF 0 IS OK, EXCEPT WHEN EXTENT SIZE >16K)
  1275. ;*
  1276. DIRNPACK::
  1277.     PUSH    H    ; SAVE REGS
  1278.     PUSH    D
  1279.     PUSH    B
  1280.     PUSH    PSW
  1281. DNPACK:
  1282.     MOV    A,B    ; DONE?
  1283.     ORA    C
  1284.     JZ    DNPAK1
  1285.     DCX    B    ; COUNT DOWN
  1286.     MOV    A,M    ; GET FIRST BYTE
  1287.     CMA        ; FLIP BITS
  1288.     ANI    80H    ; LOOK AT MOST SIG BIT
  1289.     MOV    D,A    ; SAVE IN D
  1290.     MOV    A,M    ; GET FIRST BYTE AGAIN
  1291.     ANI    7FH    ; MASK OUT MS BIT
  1292.     ORA    D    ; MASK IN NEW MOST SIG BIT
  1293.     MOV    M,A    ; PUT BYTE BACK
  1294.     ANI    80H    ; SELECTED NOW?
  1295.     JZ    DNPAK0    ; SKIP IF NOT SELECTED
  1296.     PUSH    B    ; SAVE COUNTER
  1297.     CALL    FLGCHK    ; CHECK FOR FLAGS
  1298.     POP    B    ; GET COUNTER
  1299.     JZ    DNPAK0
  1300.     MOV    A,M    ; GET BYTE
  1301.     ANI    7FH    ; DESELECT IT
  1302.     MOV    M,A    ; PUT BYTE BACK
  1303. DNPAK0:
  1304.     LXI    D,ESIZE    ; POINT TO NEXT ENTRY
  1305.     DAD    D
  1306.     JMP    DNPACK
  1307. DNPAK1:
  1308.     POP    PSW    ; RESTORE REGS
  1309.     POP    B
  1310.     POP    D
  1311.     POP    H    ; NOW FALL THRU TO DIRPACK
  1312.  
  1313. ;**************************************************************************
  1314.  
  1315. ;*
  1316. ;*  DIRECTORY PACK UTILITY -- RESTRUCTURE THE DIRECTORY TO INCLUDE ONLY
  1317. ;*    THOSE ENTRIES MARKED BY DIRSEL
  1318. ;*
  1319. ;*  ON INPUT, HL PTS TO DIRECTORY BUFFER AND BC=NUMBER OF FILES
  1320. ;*  ON EXIT, BC=NUMBER OF SELECTED FILES
  1321. ;*  REQUIRED SIDE EFFECT IS THAT FLAG EXTENT (SET BY DIR::) BE CORRECT
  1322. ;*    (IN MOST CASES, DEFAULT OF 0 IS OK, EXCEPT WHEN EXTENT SIZE >16K)
  1323. ;*
  1324. DIRPACK::
  1325.     PUSH    H    ; SAVE REGS
  1326.     PUSH    D
  1327.     PUSH    PSW
  1328.     PUSH    H    ; SAVE HL
  1329.     LXI    H,0
  1330.     SHLD    FCOUNT    ; INIT FILE COUNT
  1331.     POP    H    ; GET HL
  1332.     SHLD    DIRBUF    ; SAVE PTR
  1333.     PUSH    B    ; SAVE COUNTER
  1334. DPLOOP:
  1335.     POP    B    ; GET COUNTER
  1336.     MOV    A,B    ; CHECK FOR DONE
  1337.     ORA    C
  1338.     JZ    DPDONE
  1339.     DCX    B    ; COUNT DOWN
  1340.     PUSH    B    ; SAVE COUNTER
  1341.     MOV    A,M    ; GET 1ST BYTE OF ENTRY
  1342.     ANI    80H    ; SELECTED?
  1343.     JZ    DPNEXT
  1344. ;*  FOUND SELECTED ENTRY
  1345.     MOV    A,M    ; CLEAR MSB OF SELECTED ENTRY
  1346.     ANI    7FH
  1347.     MOV    M,A
  1348.     PUSH    H    ; SAVE PTR
  1349.     LHLD    FCOUNT    ; INCREMENT FILE COUNT
  1350.     INX    H
  1351.     SHLD    FCOUNT
  1352.     POP    D    ; PT TO CURRENT ENTRY IN DE
  1353.     LHLD    DIRBUF    ; PT TO NEXT ENTRY POSITION
  1354.     XCHG        ; HL PTS TO CURRENT, DE PTS TO NEXT ENTRY
  1355.     MVI    B,ESIZE    ; COPY ENTRY
  1356.     CALL    MOVE
  1357.     XCHG        ; HL PTS TO NEXT ENTRY
  1358.     SHLD    DIRBUF    ; SAVE IT
  1359.     XCHG        ; HL PTS TO NEXT ENTRY TO CHECK
  1360.     JMP    DPLOOP    ; CONTINUE
  1361. ;*  SKIP TO NEXT ENTRY
  1362. DPNEXT:
  1363.     LXI    B,ESIZE    ; SKIP ENTRY
  1364.     DAD    B
  1365.     JMP    DPLOOP    ; CONTINUE
  1366. ;*  COMPRESSION COMPLETE -- SET UP RETURNED VALUES
  1367. DPDONE:
  1368.     LHLD    FCOUNT    ; PUT FILE COUNT
  1369.     MOV    B,H    ; ... IN BC
  1370.     MOV    C,L
  1371.     POP    PSW    ; RESTORE REGS
  1372.     POP    D
  1373.     POP    H
  1374.     RET
  1375.  
  1376.     END
  1377.